Compare commits
7 Commits
7d694de307
..
multy
| Author | SHA1 | Date | |
|---|---|---|---|
| 8c2227432c | |||
| 84433160fe | |||
| 588d11a9ff | |||
| 3df2a0af58 | |||
| 832e539a96 | |||
| 4e6c645938 | |||
| 1869dbf054 |
@@ -1,7 +1,3 @@
|
|||||||
# Godot 4+ specific ignores
|
# Godot 4+ specific ignores
|
||||||
.godot/
|
.godot/
|
||||||
.build/
|
|
||||||
/android/
|
/android/
|
||||||
/logs
|
|
||||||
|
|
||||||
*.log
|
|
||||||
|
|||||||
Vendored
-3
@@ -1,3 +0,0 @@
|
|||||||
{
|
|
||||||
"godotTools.editorPath.godot4": "c:\\Program Files (x86)\\Godot\\Godot_v4.7-stable_win64.exe"
|
|
||||||
}
|
|
||||||
+43
-159
@@ -1,7 +1,5 @@
|
|||||||
class_name ItemContainer
|
|
||||||
extends Node3D
|
extends Node3D
|
||||||
|
|
||||||
@export var enabled: bool = true
|
|
||||||
@export var target_group : String # Items with this tag can be added to the container
|
@export var target_group : String # Items with this tag can be added to the container
|
||||||
@export var meal_positions: Array[Node3D] = []
|
@export var meal_positions: Array[Node3D] = []
|
||||||
@export var side_positions: Array[Node3D] = []
|
@export var side_positions: Array[Node3D] = []
|
||||||
@@ -24,178 +22,64 @@ func _ready() -> void:
|
|||||||
push_error("XRPickable node not found in container.gd")
|
push_error("XRPickable node not found in container.gd")
|
||||||
|
|
||||||
|
|
||||||
# Absorbing items is a server decision (the container's holder is server-
|
|
||||||
# snapped into a station, matching table.gd/hob.gd's convention).
|
|
||||||
func _on_body_entered(body: Node3D) -> void:
|
func _on_body_entered(body: Node3D) -> void:
|
||||||
|
# Container fill mutates world state (reparent/freeze); run only on the
|
||||||
|
# world owner. Item transforms replicate to clients via each item's
|
||||||
|
# MultiplayerSynchronizer (global_transform), so contents follow the plate.
|
||||||
if not NetworkManager.owns_world():
|
if not NetworkManager.owns_world():
|
||||||
return
|
return
|
||||||
print("Container enabled: ", enabled)
|
|
||||||
if not enabled:
|
|
||||||
print("Container disabled in _on_body_entered body")
|
|
||||||
return
|
|
||||||
if not body.is_in_group(target_group):
|
if not body.is_in_group(target_group):
|
||||||
return
|
return
|
||||||
print("Container _on_body_entered body: ", body)
|
|
||||||
|
|
||||||
|
|
||||||
# If one of us is in a station
|
|
||||||
var picked_by = xr_pickable.get_picked_up_by()
|
var picked_by = xr_pickable.get_picked_up_by()
|
||||||
var body_pickable = body as XRToolsPickable
|
if picked_by and picked_by.is_in_group("station"):
|
||||||
var body_picked_by = body_pickable.get_picked_up_by() if body_pickable else null
|
|
||||||
if (picked_by and picked_by.is_in_group("station")) or (body_picked_by and body_picked_by.is_in_group("station")):
|
# If compatible and enough space, add item
|
||||||
|
|
||||||
# If enough space, add item
|
|
||||||
var food_item = body.get_node("FoodItem")
|
var food_item = body.get_node("FoodItem")
|
||||||
print("Container in station found %s of type %s: %s" % [target_group, FoodItem.Type.keys()[food_item.type], body.name])
|
print("Container in station found %s of type %s: %s" % [target_group, FoodItem.Type.keys()[food_item.type], body.name])
|
||||||
var meal_count := contained_items.filter(func(f): return f.type == FoodItem.Type.MEAL).size()
|
if food_item.type == FoodItem.Type.MEAL and _meal_container.get_child_count() < meal_positions.size():
|
||||||
var side_count := contained_items.filter(func(f): return f.type == FoodItem.Type.SIDE).size()
|
|
||||||
if food_item.type == FoodItem.Type.MEAL and meal_count < meal_positions.size():
|
|
||||||
print("Container adding meal")
|
print("Container adding meal")
|
||||||
_add_item(body)
|
_add_item(body, meal_positions, _meal_container)
|
||||||
if food_item.type == FoodItem.Type.SIDE and side_count < side_positions.size():
|
if food_item.type == FoodItem.Type.SIDE and _side_container.get_child_count() < side_positions.size():
|
||||||
print("Container adding side")
|
print("Container adding side")
|
||||||
_add_item(body)
|
_add_item(body, side_positions, _side_container)
|
||||||
|
|
||||||
|
|
||||||
|
func _add_item(item: Node3D, positions: Array[Node3D], container_root: Node3D) -> void:
|
||||||
# Contents are synced as data (ids on the plate's PlateController), not
|
|
||||||
# reparented nodes: reparenting a MultiplayerSpawner-tracked item out of
|
|
||||||
# WorldContent would despawn it on every client the instant it happened.
|
|
||||||
func _add_item(item: Node3D) -> void:
|
|
||||||
var pickable = item as XRToolsPickable
|
var pickable = item as XRToolsPickable
|
||||||
if pickable and pickable.is_picked_up():
|
var rigidbody = item as RigidBody3D
|
||||||
pickable.drop()
|
|
||||||
|
# Drop item
|
||||||
var food_node := item.get_node_or_null("FoodItem") as FoodItem
|
if pickable:
|
||||||
if not food_node:
|
if pickable.is_picked_up():
|
||||||
return
|
pickable.drop()
|
||||||
|
pickable.enabled = false
|
||||||
# Copy the data out before despawning the real item.
|
|
||||||
var data := FoodItem.new()
|
# Freeze the rigid body and disable its collisions so it doesn't fight the container
|
||||||
data.id = food_node.id
|
if rigidbody:
|
||||||
data.type = food_node.type
|
rigidbody.freeze = true
|
||||||
data.sell_value = food_node.sell_value
|
rigidbody.freeze_mode = RigidBody3D.FREEZE_MODE_KINEMATIC
|
||||||
contained_items.append(data)
|
rigidbody.process_mode = PROCESS_MODE_DISABLED
|
||||||
|
# Optional: Disable collision layer/mask so it doesn't bump into other food
|
||||||
var plate_controller := xr_pickable.get_node_or_null("PlateController") as PlateController
|
rigidbody.collision_layer = 0
|
||||||
if plate_controller:
|
rigidbody.collision_mask = 0
|
||||||
# Reassign rather than append in place. contained_ids has a setter that
|
|
||||||
# rebuilds the plate's visuals, and mutating the array never triggers it —
|
item.reparent(container_root, false) # false = discard global transform
|
||||||
# so the peer that actually added the food was the one peer that never
|
|
||||||
# redrew the plate. Remote peers looked right (the synchronizer assigns
|
# Get target position index
|
||||||
# the value there, which does fire the setter), and the stale peer only
|
var target_slot_index = container_root.get_child_count() - 1
|
||||||
# caught up if someone else took the plate and sent the value back.
|
if target_slot_index < positions.size():
|
||||||
# duplicate() keeps the Array[String] typing that the property requires.
|
item.position = positions[target_slot_index].position
|
||||||
var updated := plate_controller.contained_ids.duplicate()
|
item.rotation = positions[target_slot_index].rotation
|
||||||
updated.append(food_node.id)
|
|
||||||
plate_controller.contained_ids = updated
|
# Add to list
|
||||||
|
var food_node = item.get_node_or_null("FoodItem")
|
||||||
NetworkManager.despawn_item(item)
|
if food_node:
|
||||||
|
contained_items.append(food_node as FoodItem)
|
||||||
|
|
||||||
func erase_item(item: FoodItem) -> void:
|
|
||||||
contained_items.erase(item)
|
|
||||||
var plate_controller := xr_pickable.get_node_or_null("PlateController") as PlateController
|
|
||||||
if plate_controller:
|
|
||||||
# Same reason as _add_item: assign so the visuals actually refresh.
|
|
||||||
var remaining := plate_controller.contained_ids.duplicate()
|
|
||||||
remaining.erase(item.id)
|
|
||||||
plate_controller.contained_ids = remaining
|
|
||||||
|
|
||||||
|
|
||||||
func clear() -> void:
|
func clear() -> void:
|
||||||
contained_items.clear()
|
# delete all nodes in containers and contained_items
|
||||||
var plate_controller := xr_pickable.get_node_or_null("PlateController") as PlateController
|
pass
|
||||||
if plate_controller:
|
|
||||||
plate_controller.contained_ids = []
|
|
||||||
|
|
||||||
|
|
||||||
## Rebuilds the purely-cosmetic visual representation of the plate's contents
|
|
||||||
## from a synced id list. Runs on every peer (called from PlateController
|
|
||||||
## whenever contained_ids changes, whether set locally or by the network).
|
|
||||||
func refresh_visuals(ids: Array[String]) -> void:
|
|
||||||
for child in _meal_container.get_children():
|
|
||||||
child.queue_free()
|
|
||||||
for child in _side_container.get_children():
|
|
||||||
child.queue_free()
|
|
||||||
|
|
||||||
var meal_idx := 0
|
|
||||||
var side_idx := 0
|
|
||||||
for id in ids:
|
|
||||||
var scene := RecipeManager.get_item_scene(id)
|
|
||||||
if not scene:
|
|
||||||
continue
|
|
||||||
var visual := scene.instantiate()
|
|
||||||
var food_node := visual.get_node_or_null("FoodItem") as FoodItem
|
|
||||||
|
|
||||||
var container_root: Node3D
|
|
||||||
var positions: Array[Node3D]
|
|
||||||
var idx: int
|
|
||||||
if food_node and food_node.type == FoodItem.Type.MEAL and meal_idx < meal_positions.size():
|
|
||||||
container_root = _meal_container
|
|
||||||
positions = meal_positions
|
|
||||||
idx = meal_idx
|
|
||||||
meal_idx += 1
|
|
||||||
elif food_node and food_node.type == FoodItem.Type.SIDE and side_idx < side_positions.size():
|
|
||||||
container_root = _side_container
|
|
||||||
positions = side_positions
|
|
||||||
idx = side_idx
|
|
||||||
side_idx += 1
|
|
||||||
else:
|
|
||||||
visual.queue_free()
|
|
||||||
continue
|
|
||||||
|
|
||||||
_make_cosmetic(visual)
|
|
||||||
container_root.add_child(visual)
|
|
||||||
# Must happen after add_child: entering the world is what puts the body
|
|
||||||
# into the physics space, so it can only be taken out again afterwards.
|
|
||||||
_remove_from_physics(visual)
|
|
||||||
visual.position = positions[idx].position
|
|
||||||
visual.rotation = positions[idx].rotation
|
|
||||||
|
|
||||||
|
|
||||||
# Strip interactivity/networking from a display-only copy: it's not spawned
|
|
||||||
# through NetworkManager, so it must never try to sync (its NetPickable child,
|
|
||||||
# if any, would have no corresponding replicated identity on other peers) or
|
|
||||||
# be grabbable/collidable.
|
|
||||||
func _make_cosmetic(visual: Node3D) -> void:
|
|
||||||
var net_pickable := visual.get_node_or_null("NetPickable")
|
|
||||||
if net_pickable:
|
|
||||||
# Detach and free it outright rather than queue_free(): this runs before
|
|
||||||
# `visual` is added to the tree, and a merely-queued node still enters the
|
|
||||||
# tree with its parent and runs _ready() (which starts syncing and logging)
|
|
||||||
# before the queued deletion lands at the end of the frame.
|
|
||||||
visual.remove_child(net_pickable)
|
|
||||||
net_pickable.free()
|
|
||||||
if visual is RigidBody3D:
|
|
||||||
visual.freeze = true
|
|
||||||
# STATIC, not KINEMATIC: a kinematic body is still driven by the physics
|
|
||||||
# engine (see _remove_from_physics), and "static decoration" is what this
|
|
||||||
# actually is.
|
|
||||||
visual.freeze_mode = RigidBody3D.FREEZE_MODE_STATIC
|
|
||||||
visual.collision_layer = 0
|
|
||||||
visual.collision_mask = 0
|
|
||||||
if visual is XRToolsPickable:
|
|
||||||
visual.enabled = false
|
|
||||||
visual.set_process(false)
|
|
||||||
visual.set_physics_process(false)
|
|
||||||
|
|
||||||
|
|
||||||
# Take a display-only copy out of the physics simulation completely.
|
|
||||||
#
|
|
||||||
# Freezing is not enough. Under Jolt (this project's physics engine) a frozen
|
|
||||||
# KINEMATIC RigidBody3D is still simulated: it is driven toward its target
|
|
||||||
# transform by velocity rather than being teleported. Parented to a plate that
|
|
||||||
# gets picked up and carried, it therefore lags behind, keeps its velocity, and
|
|
||||||
# overshoots — so the food visibly slid off the plate and ended up metres away,
|
|
||||||
# differently on each peer since each simulates its own copy. A body with no
|
|
||||||
# space is never touched by the engine, so it simply follows its parent.
|
|
||||||
func _remove_from_physics(visual: Node3D) -> void:
|
|
||||||
if visual is RigidBody3D:
|
|
||||||
PhysicsServer3D.body_set_space((visual as RigidBody3D).get_rid(), RID())
|
|
||||||
var despawning_item = visual.get_node_or_null("DespawningItem")
|
|
||||||
if despawning_item:
|
|
||||||
NetworkManager.despawn_item(despawning_item)
|
|
||||||
|
|
||||||
|
|
||||||
#plate (Pickalbe)
|
#plate (Pickalbe)
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
[ext_resource type="Script" uid="uid://6lyhyial1fh5" path="res://Containers/container.gd" id="1_r4cle"]
|
[ext_resource type="Script" uid="uid://6lyhyial1fh5" path="res://Containers/container.gd" id="1_r4cle"]
|
||||||
|
|
||||||
[sub_resource type="SphereShape3D" id="SphereShape3D_vlqg6"]
|
[sub_resource type="SphereShape3D" id="SphereShape3D_vlqg6"]
|
||||||
radius = 0.3
|
radius = 0.2
|
||||||
|
|
||||||
[node name="Container" type="Node3D" unique_id=377793422 node_paths=PackedStringArray("meal_positions")]
|
[node name="Container" type="Node3D" unique_id=377793422 node_paths=PackedStringArray("meal_positions")]
|
||||||
script = ExtResource("1_r4cle")
|
script = ExtResource("1_r4cle")
|
||||||
|
|||||||
+12
-73
@@ -2,13 +2,17 @@
|
|||||||
|
|
||||||
[ext_resource type="Script" uid="uid://bfrlpbsqg5lqr" path="res://addons/godot-xr-tools/objects/pickable.gd" id="1_nq5sa"]
|
[ext_resource type="Script" uid="uid://bfrlpbsqg5lqr" path="res://addons/godot-xr-tools/objects/pickable.gd" id="1_nq5sa"]
|
||||||
[ext_resource type="PackedScene" uid="uid://du31pqeytu8as" path="res://Containers/container.tscn" id="1_s5yhh"]
|
[ext_resource type="PackedScene" uid="uid://du31pqeytu8as" path="res://Containers/container.tscn" id="1_s5yhh"]
|
||||||
[ext_resource type="Script" uid="uid://iqjqsk4v6qfh" path="res://Containers/plate_controller.gd" id="1_vjsmi"]
|
|
||||||
[ext_resource type="PackedScene" uid="uid://c25yxb0vt53vc" path="res://addons/godot-xr-tools/objects/grab_points/grab_point_hand_left.tscn" id="2_3bkoa"]
|
[ext_resource type="PackedScene" uid="uid://c25yxb0vt53vc" path="res://addons/godot-xr-tools/objects/grab_points/grab_point_hand_left.tscn" id="2_3bkoa"]
|
||||||
[ext_resource type="Animation" uid="uid://db62hs5s4n2b3" path="res://addons/godot-xr-tools/hands/animations/left/Grip 4.res" id="3_6v47p"]
|
[ext_resource type="Animation" uid="uid://db62hs5s4n2b3" path="res://addons/godot-xr-tools/hands/animations/left/Grip 4.res" id="3_6v47p"]
|
||||||
[ext_resource type="Script" uid="uid://dvobm6vcfnqe8" path="res://addons/godot-xr-tools/hands/poses/hand_pose_settings.gd" id="4_dhtvl"]
|
[ext_resource type="Script" uid="uid://dvobm6vcfnqe8" path="res://addons/godot-xr-tools/hands/poses/hand_pose_settings.gd" id="4_dhtvl"]
|
||||||
[ext_resource type="PackedScene" uid="uid://ctw7nbntd5pcj" path="res://addons/godot-xr-tools/objects/grab_points/grab_point_hand_right.tscn" id="5_vlcpl"]
|
[ext_resource type="PackedScene" uid="uid://ctw7nbntd5pcj" path="res://addons/godot-xr-tools/objects/grab_points/grab_point_hand_right.tscn" id="5_vlcpl"]
|
||||||
[ext_resource type="Animation" uid="uid://d1xnpyc08njjx" path="res://addons/godot-xr-tools/hands/animations/right/Grip 4.res" id="6_el51w"]
|
[ext_resource type="Animation" uid="uid://d1xnpyc08njjx" path="res://addons/godot-xr-tools/hands/animations/right/Grip 4.res" id="6_el51w"]
|
||||||
[ext_resource type="Script" uid="uid://bwd0pe2udb5xo" path="res://Net/net_pickable.gd" id="20_netpk"]
|
[ext_resource type="Script" path="res://Prefabs/net_pickable.gd" id="7_net"]
|
||||||
|
|
||||||
|
[sub_resource type="SceneReplicationConfig" id="Repl_item"]
|
||||||
|
properties/0/path = NodePath(".:global_transform")
|
||||||
|
properties/0/spawn = true
|
||||||
|
properties/0/replication_mode = 1
|
||||||
|
|
||||||
[sub_resource type="CylinderShape3D" id="CylinderShape3D_kek77"]
|
[sub_resource type="CylinderShape3D" id="CylinderShape3D_kek77"]
|
||||||
height = 0.0635376
|
height = 0.0635376
|
||||||
@@ -24,35 +28,12 @@ script = ExtResource("4_dhtvl")
|
|||||||
closed_pose = ExtResource("6_el51w")
|
closed_pose = ExtResource("6_el51w")
|
||||||
metadata/_custom_type_script = "uid://dvobm6vcfnqe8"
|
metadata/_custom_type_script = "uid://dvobm6vcfnqe8"
|
||||||
|
|
||||||
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_vlqg6"]
|
|
||||||
albedo_color = Color(0.36656043, 0.16690676, 0.12531222, 1)
|
|
||||||
|
|
||||||
[sub_resource type="SceneReplicationConfig" id="SceneReplicationConfig_np_plate"]
|
|
||||||
properties/0/path = NodePath(".:position")
|
|
||||||
properties/0/spawn = false
|
|
||||||
properties/0/replication_mode = 1
|
|
||||||
properties/1/path = NodePath(".:quaternion")
|
|
||||||
properties/1/spawn = false
|
|
||||||
properties/1/replication_mode = 1
|
|
||||||
properties/2/path = NodePath("NetPickable:net_held_by")
|
|
||||||
properties/2/spawn = true
|
|
||||||
properties/2/replication_mode = 1
|
|
||||||
properties/3/path = NodePath("PlateController:contained_ids")
|
|
||||||
properties/3/spawn = true
|
|
||||||
properties/3/replication_mode = 1
|
|
||||||
properties/4/path = NodePath("PlateController:is_dirty")
|
|
||||||
properties/4/spawn = true
|
|
||||||
properties/4/replication_mode = 1
|
|
||||||
|
|
||||||
[node name="Plate" type="RigidBody3D" unique_id=190487773]
|
[node name="Plate" type="RigidBody3D" unique_id=190487773]
|
||||||
collision_layer = 4
|
collision_layer = 4
|
||||||
collision_mask = 196615
|
collision_mask = 196615
|
||||||
freeze_mode = 1
|
freeze_mode = 1
|
||||||
script = ExtResource("1_nq5sa")
|
script = ExtResource("1_nq5sa")
|
||||||
|
|
||||||
[node name="PlateController" type="Node" parent="." unique_id=1503264193]
|
|
||||||
script = ExtResource("1_vjsmi")
|
|
||||||
|
|
||||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="." unique_id=1365637864]
|
[node name="CollisionShape3D" type="CollisionShape3D" parent="." unique_id=1365637864]
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.007171631, 0)
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.007171631, 0)
|
||||||
shape = SubResource("CylinderShape3D_kek77")
|
shape = SubResource("CylinderShape3D_kek77")
|
||||||
@@ -86,6 +67,12 @@ hand_pose = SubResource("Resource_2hcq0")
|
|||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.16517048, 0.042291984, -0.08604182)
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.16517048, 0.042291984, -0.08604182)
|
||||||
hand_pose = SubResource("Resource_dlngj")
|
hand_pose = SubResource("Resource_dlngj")
|
||||||
|
|
||||||
|
[node name="NetPickable" type="Node" parent="."]
|
||||||
|
script = ExtResource("7_net")
|
||||||
|
|
||||||
|
[node name="MultiplayerSynchronizer" type="MultiplayerSynchronizer" parent="."]
|
||||||
|
replication_config = SubResource("Repl_item")
|
||||||
|
|
||||||
[node name="Container" parent="." unique_id=377793422 node_paths=PackedStringArray("meal_positions", "side_positions") instance=ExtResource("1_s5yhh")]
|
[node name="Container" parent="." unique_id=377793422 node_paths=PackedStringArray("meal_positions", "side_positions") instance=ExtResource("1_s5yhh")]
|
||||||
target_group = "platalbe_item"
|
target_group = "platalbe_item"
|
||||||
meal_positions = [NodePath("MealPositions/Slot1")]
|
meal_positions = [NodePath("MealPositions/Slot1")]
|
||||||
@@ -108,51 +95,3 @@ transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.08457637, 0, 0.08950478)
|
|||||||
|
|
||||||
[node name="Slot4" type="Node3D" parent="Container/SidePositions" unique_id=379534402]
|
[node name="Slot4" type="Node3D" parent="Container/SidePositions" unique_id=379534402]
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.06938871, 0, 0.072598234)
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.06938871, 0, 0.072598234)
|
||||||
|
|
||||||
[node name="Dirty" type="Node3D" parent="." unique_id=319270152]
|
|
||||||
visible = false
|
|
||||||
|
|
||||||
[node name="CSGCylinder3D" type="CSGCylinder3D" parent="Dirty" unique_id=1075901752]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.074060306, -1.4901161e-08, -0.021821946)
|
|
||||||
radius = 0.02
|
|
||||||
height = 0.005
|
|
||||||
sides = 16
|
|
||||||
material = SubResource("StandardMaterial3D_vlqg6")
|
|
||||||
|
|
||||||
[node name="CSGCylinder3D2" type="CSGCylinder3D" parent="Dirty" unique_id=1566886557]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.035480514, 0, 0.09590546)
|
|
||||||
radius = 0.04
|
|
||||||
height = 0.005
|
|
||||||
sides = 16
|
|
||||||
material = SubResource("StandardMaterial3D_vlqg6")
|
|
||||||
|
|
||||||
[node name="CSGCylinder3D3" type="CSGCylinder3D" parent="Dirty" unique_id=1761966340]
|
|
||||||
transform = Transform3D(0.9644101, 0.26441094, 0, -0.26441094, 0.9644101, 0, 0, 0, 1, -0.11377221, 0.005669184, 0.010442272)
|
|
||||||
radius = 0.05
|
|
||||||
height = 0.005
|
|
||||||
sides = 16
|
|
||||||
material = SubResource("StandardMaterial3D_vlqg6")
|
|
||||||
|
|
||||||
[node name="CSGCylinder3D4" type="CSGCylinder3D" parent="Dirty" unique_id=1869071428]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.023516195, 0, -0.088724144)
|
|
||||||
radius = 0.024
|
|
||||||
height = 0.005
|
|
||||||
sides = 16
|
|
||||||
material = SubResource("StandardMaterial3D_vlqg6")
|
|
||||||
|
|
||||||
[node name="CSGTorus3D" type="CSGTorus3D" parent="Dirty" unique_id=753275027]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.0009794924, -0.005010009, -0.0004204195)
|
|
||||||
inner_radius = 0.10664626
|
|
||||||
outer_radius = 0.14543402
|
|
||||||
sides = 16
|
|
||||||
material = SubResource("StandardMaterial3D_vlqg6")
|
|
||||||
|
|
||||||
[node name="CSGPolygon3D" type="CSGPolygon3D" parent="Dirty" unique_id=280929999]
|
|
||||||
transform = Transform3D(0.21189868, 0, 0, 0, -9.2623855e-09, 0.21189868, 0, -0.21189868, -9.2623855e-09, -0.04347625, 0, 0.017095774)
|
|
||||||
polygon = PackedVector2Array(-0.053057775, 0.2586278, 0.09469998, 0.40791017, 0.31746316, 0.26044407, 0.4514293, -0.05809097, 0.105977096, -0.11683442, -4.3913722e-05, 0.02302903)
|
|
||||||
depth = 0.02
|
|
||||||
material = SubResource("StandardMaterial3D_vlqg6")
|
|
||||||
|
|
||||||
[node name="NetPickable" type="MultiplayerSynchronizer" parent="." unique_id=1770751620]
|
|
||||||
replication_config = SubResource("SceneReplicationConfig_np_plate")
|
|
||||||
script = ExtResource("20_netpk")
|
|
||||||
|
|||||||
@@ -1,48 +0,0 @@
|
|||||||
class_name PlateController
|
|
||||||
extends Node
|
|
||||||
|
|
||||||
@onready var dirty_node: Node3D = $"../Dirty"
|
|
||||||
@onready var container: ItemContainer = $"../Container"
|
|
||||||
|
|
||||||
@export var is_dirty: bool = false
|
|
||||||
|
|
||||||
## Synced plate contents (item ids), replacing reparented child nodes so
|
|
||||||
## contents survive replication (a MultiplayerSpawner-tracked item would
|
|
||||||
## despawn on every client the instant it was reparented out of WorldContent).
|
|
||||||
## Server writes it via ItemContainer; every peer (server included) renders
|
|
||||||
## the cosmetic result via the setter below.
|
|
||||||
@export var contained_ids: Array[String] = []: set = _set_contained_ids
|
|
||||||
|
|
||||||
|
|
||||||
func _ready() -> void:
|
|
||||||
if not dirty_node:
|
|
||||||
push_error("Plate is missing its dirty_node")
|
|
||||||
dirty_node.visible = is_dirty
|
|
||||||
|
|
||||||
|
|
||||||
func _process(_delta: float) -> void:
|
|
||||||
if is_dirty:
|
|
||||||
container.enabled = false
|
|
||||||
dirty_node.visible = true
|
|
||||||
else:
|
|
||||||
container.enabled = true
|
|
||||||
dirty_node.visible = false
|
|
||||||
|
|
||||||
|
|
||||||
func _set_contained_ids(value: Array[String]) -> void:
|
|
||||||
# Only rebuild when the contents actually changed. This property is
|
|
||||||
# replicated in ALWAYS mode, so the synchronizer assigns it every network
|
|
||||||
# tick on every peer that doesn't own the plate — and refresh_visuals()
|
|
||||||
# frees and re-instantiates a scene per item each time. That was thousands
|
|
||||||
# of throwaway nodes per run (and a log line from each one's NetPickable).
|
|
||||||
if contained_ids == value:
|
|
||||||
return
|
|
||||||
contained_ids = value
|
|
||||||
# Deferred: this can be written by the replicated spawn payload before
|
|
||||||
# this node's own @onready vars (container) have resolved.
|
|
||||||
_refresh_visuals.call_deferred()
|
|
||||||
|
|
||||||
|
|
||||||
func _refresh_visuals() -> void:
|
|
||||||
if container:
|
|
||||||
container.refresh_visuals(contained_ids)
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
uid://iqjqsk4v6qfh
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
class_name GameManager
|
|
||||||
extends Node
|
|
||||||
|
|
||||||
static var money: int
|
|
||||||
static var meals_in_play: Array[String]
|
|
||||||
static var sides_in_play: Array[String]
|
|
||||||
|
|
||||||
enum GameState {
|
|
||||||
RUNNING,
|
|
||||||
GAME_OVER
|
|
||||||
}
|
|
||||||
static var game_state: GameState = GameState.RUNNING
|
|
||||||
|
|
||||||
|
|
||||||
static func _restart():
|
|
||||||
print("restart Game")
|
|
||||||
game_state = GameState.RUNNING
|
|
||||||
|
|
||||||
|
|
||||||
static func get_random_meal() -> String:
|
|
||||||
if meals_in_play.size() == 0:
|
|
||||||
push_error("GameManager: get_random_meal() called but meals_in_play is empty")
|
|
||||||
return ""
|
|
||||||
var rand_index = randi() % meals_in_play.size()
|
|
||||||
print("GameManager: get_random_meal() returning ", meals_in_play[rand_index])
|
|
||||||
return meals_in_play[rand_index]
|
|
||||||
|
|
||||||
|
|
||||||
static func get_random_side() -> String:
|
|
||||||
if sides_in_play.size() == 0:
|
|
||||||
push_error("GameManager: get_random_side() called but sides_in_play is empty")
|
|
||||||
return ""
|
|
||||||
var rand_index = randi() % sides_in_play.size()
|
|
||||||
print("GameManager: get_random_side() returning ", sides_in_play[rand_index])
|
|
||||||
return sides_in_play[rand_index]
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static func game_over():
|
|
||||||
print("Game Over")
|
|
||||||
game_state = GameState.GAME_OVER
|
|
||||||
Signals.game_over.emit()
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
uid://y4sol8l8vih1
|
|
||||||
+10
-24
@@ -7,9 +7,8 @@
|
|||||||
[ext_resource type="PackedScene" uid="uid://c25yxb0vt53vc" path="res://addons/godot-xr-tools/objects/grab_points/grab_point_hand_left.tscn" id="5_wqyr2"]
|
[ext_resource type="PackedScene" uid="uid://c25yxb0vt53vc" path="res://addons/godot-xr-tools/objects/grab_points/grab_point_hand_left.tscn" id="5_wqyr2"]
|
||||||
[ext_resource type="Animation" uid="uid://bediglpx0rj7i" path="res://addons/godot-xr-tools/hands/animations/left/Grip 5.res" id="6_ftab3"]
|
[ext_resource type="Animation" uid="uid://bediglpx0rj7i" path="res://addons/godot-xr-tools/hands/animations/left/Grip 5.res" id="6_ftab3"]
|
||||||
[ext_resource type="PackedScene" uid="uid://3lr2dhy62rhk" path="res://Prefabs/combinable_item.tscn" id="7_wb51u"]
|
[ext_resource type="PackedScene" uid="uid://3lr2dhy62rhk" path="res://Prefabs/combinable_item.tscn" id="7_wb51u"]
|
||||||
[ext_resource type="PackedScene" uid="uid://bfj80jh13t6e5" path="res://Prefabs/food_item.tscn" id="8_t9y3x"]
|
[ext_resource type="Script" uid="uid://coidnv8b2yvxr" path="res://Prefabs/combine_recipe.gd" id="8_wqyr2"]
|
||||||
[ext_resource type="PackedScene" uid="uid://b5ukku8i0hilb" path="res://Prefabs/despawning_item.tscn" id="10_46e7r"]
|
[ext_resource type="PackedScene" uid="uid://b3m2ag8g5rj4r" path="res://Items/hamburger.tscn" id="9_wb51u"]
|
||||||
[ext_resource type="Script" uid="uid://bwd0pe2udb5xo" path="res://Net/net_pickable.gd" id="20_netpk"]
|
|
||||||
|
|
||||||
[sub_resource type="CylinderShape3D" id="CylinderShape3D_vlqg6"]
|
[sub_resource type="CylinderShape3D" id="CylinderShape3D_vlqg6"]
|
||||||
height = 0.10708985
|
height = 0.10708985
|
||||||
@@ -28,16 +27,11 @@ metadata/_custom_type_script = "uid://dvobm6vcfnqe8"
|
|||||||
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_hoqox"]
|
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_hoqox"]
|
||||||
albedo_color = Color(0.6784191, 0.54546416, 0.016760282, 1)
|
albedo_color = Color(0.6784191, 0.54546416, 0.016760282, 1)
|
||||||
|
|
||||||
[sub_resource type="SceneReplicationConfig" id="SceneReplicationConfig_np_buns"]
|
[sub_resource type="Resource" id="Resource_hwyyd"]
|
||||||
properties/0/path = NodePath(".:position")
|
script = ExtResource("8_wqyr2")
|
||||||
properties/0/spawn = false
|
ingredient_id = &"cooked_burger"
|
||||||
properties/0/replication_mode = 1
|
result = ExtResource("9_wb51u")
|
||||||
properties/1/path = NodePath(".:quaternion")
|
metadata/_custom_type_script = "uid://coidnv8b2yvxr"
|
||||||
properties/1/spawn = false
|
|
||||||
properties/1/replication_mode = 1
|
|
||||||
properties/2/path = NodePath("NetPickable:net_held_by")
|
|
||||||
properties/2/spawn = true
|
|
||||||
properties/2/replication_mode = 1
|
|
||||||
|
|
||||||
[node name="BurgerBuns" unique_id=1088240294 instance=ExtResource("1_g1t48")]
|
[node name="BurgerBuns" unique_id=1088240294 instance=ExtResource("1_g1t48")]
|
||||||
|
|
||||||
@@ -80,14 +74,6 @@ sides = 16
|
|||||||
cone = true
|
cone = true
|
||||||
material = SubResource("StandardMaterial3D_hoqox")
|
material = SubResource("StandardMaterial3D_hoqox")
|
||||||
|
|
||||||
[node name="FoodItem" parent="." index="4" unique_id=123456789 instance=ExtResource("8_t9y3x")]
|
[node name="CombinableItem" parent="." index="4" unique_id=996936271 instance=ExtResource("7_wb51u")]
|
||||||
id = "burger_buns"
|
id = &"burger_buns"
|
||||||
type = 2
|
recipes = Array[ExtResource("8_wqyr2")]([SubResource("Resource_hwyyd")])
|
||||||
|
|
||||||
[node name="CombinableItem" parent="." index="5" unique_id=996936271 instance=ExtResource("7_wb51u")]
|
|
||||||
|
|
||||||
[node name="NetPickable" type="MultiplayerSynchronizer" parent="." index="6" unique_id=2086885420]
|
|
||||||
replication_config = SubResource("SceneReplicationConfig_np_buns")
|
|
||||||
script = ExtResource("20_netpk")
|
|
||||||
|
|
||||||
[node name="DespawningItem" parent="." index="7" unique_id=303090111 instance=ExtResource("10_46e7r")]
|
|
||||||
|
|||||||
+11
-25
@@ -6,12 +6,15 @@
|
|||||||
[ext_resource type="Script" uid="uid://dvobm6vcfnqe8" path="res://addons/godot-xr-tools/hands/poses/hand_pose_settings.gd" id="4_mgacb"]
|
[ext_resource type="Script" uid="uid://dvobm6vcfnqe8" path="res://addons/godot-xr-tools/hands/poses/hand_pose_settings.gd" id="4_mgacb"]
|
||||||
[ext_resource type="PackedScene" uid="uid://ctw7nbntd5pcj" path="res://addons/godot-xr-tools/objects/grab_points/grab_point_hand_right.tscn" id="5_vw7i6"]
|
[ext_resource type="PackedScene" uid="uid://ctw7nbntd5pcj" path="res://addons/godot-xr-tools/objects/grab_points/grab_point_hand_right.tscn" id="5_vw7i6"]
|
||||||
[ext_resource type="Animation" uid="uid://d1xnpyc08njjx" path="res://addons/godot-xr-tools/hands/animations/right/Grip 4.res" id="6_cp3eg"]
|
[ext_resource type="Animation" uid="uid://d1xnpyc08njjx" path="res://addons/godot-xr-tools/hands/animations/right/Grip 4.res" id="6_cp3eg"]
|
||||||
[ext_resource type="PackedScene" uid="uid://bfj80jh13t6e5" path="res://Prefabs/food_item.tscn" id="7_mde49"]
|
[ext_resource type="Script" path="res://Prefabs/net_pickable.gd" id="7_net"]
|
||||||
[ext_resource type="PackedScene" uid="uid://3lr2dhy62rhk" path="res://Prefabs/combinable_item.tscn" id="8_wmrff"]
|
|
||||||
[ext_resource type="PackedScene" uid="uid://b5ukku8i0hilb" path="res://Prefabs/despawning_item.tscn" id="10_6ypk4"]
|
[sub_resource type="SceneReplicationConfig" id="Repl_item"]
|
||||||
[ext_resource type="Script" uid="uid://bwd0pe2udb5xo" path="res://Net/net_pickable.gd" id="20_netpk"]
|
properties/0/path = NodePath(".:global_transform")
|
||||||
|
properties/0/spawn = true
|
||||||
|
properties/0/replication_mode = 1
|
||||||
|
|
||||||
[sub_resource type="CylinderShape3D" id="CylinderShape3D_gkni8"]
|
[sub_resource type="CylinderShape3D" id="CylinderShape3D_gkni8"]
|
||||||
|
custom_solver_bias = 0.1
|
||||||
height = 0.1
|
height = 0.1
|
||||||
radius = 0.1
|
radius = 0.1
|
||||||
|
|
||||||
@@ -34,17 +37,6 @@ script = ExtResource("4_mgacb")
|
|||||||
closed_pose = ExtResource("6_cp3eg")
|
closed_pose = ExtResource("6_cp3eg")
|
||||||
metadata/_custom_type_script = "uid://dvobm6vcfnqe8"
|
metadata/_custom_type_script = "uid://dvobm6vcfnqe8"
|
||||||
|
|
||||||
[sub_resource type="SceneReplicationConfig" id="SceneReplicationConfig_np_charcoal"]
|
|
||||||
properties/0/path = NodePath(".:position")
|
|
||||||
properties/0/spawn = false
|
|
||||||
properties/0/replication_mode = 1
|
|
||||||
properties/1/path = NodePath(".:quaternion")
|
|
||||||
properties/1/spawn = false
|
|
||||||
properties/1/replication_mode = 1
|
|
||||||
properties/2/path = NodePath("NetPickable:net_held_by")
|
|
||||||
properties/2/spawn = true
|
|
||||||
properties/2/replication_mode = 1
|
|
||||||
|
|
||||||
[node name="PickableObject" unique_id=1675596942 instance=ExtResource("1_r73y2")]
|
[node name="PickableObject" unique_id=1675596942 instance=ExtResource("1_r73y2")]
|
||||||
|
|
||||||
[node name="CollisionShape3D" parent="." index="0"]
|
[node name="CollisionShape3D" parent="." index="0"]
|
||||||
@@ -61,14 +53,8 @@ hand_pose = SubResource("Resource_lc22d")
|
|||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.06531982, 0.042291984, -0.08604182)
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.06531982, 0.042291984, -0.08604182)
|
||||||
hand_pose = SubResource("Resource_qyiot")
|
hand_pose = SubResource("Resource_qyiot")
|
||||||
|
|
||||||
[node name="FoodItem" parent="." index="4" unique_id=345678912 instance=ExtResource("7_mde49")]
|
[node name="NetPickable" type="Node" parent="." index="4"]
|
||||||
id = "charcoal"
|
script = ExtResource("7_net")
|
||||||
type = 2
|
|
||||||
|
|
||||||
[node name="CombinableItem" parent="." index="5" unique_id=996936271 instance=ExtResource("8_wmrff")]
|
[node name="MultiplayerSynchronizer" type="MultiplayerSynchronizer" parent="." index="5"]
|
||||||
|
replication_config = SubResource("Repl_item")
|
||||||
[node name="NetPickable" type="MultiplayerSynchronizer" parent="." index="6" unique_id=1070495412]
|
|
||||||
replication_config = SubResource("SceneReplicationConfig_np_charcoal")
|
|
||||||
script = ExtResource("20_netpk")
|
|
||||||
|
|
||||||
[node name="DespawningItem" parent="." index="7" unique_id=303090111 instance=ExtResource("10_6ypk4")]
|
|
||||||
|
|||||||
+25
-19
@@ -7,9 +7,16 @@
|
|||||||
[ext_resource type="PackedScene" uid="uid://ctw7nbntd5pcj" path="res://addons/godot-xr-tools/objects/grab_points/grab_point_hand_right.tscn" id="5_a0a5b"]
|
[ext_resource type="PackedScene" uid="uid://ctw7nbntd5pcj" path="res://addons/godot-xr-tools/objects/grab_points/grab_point_hand_right.tscn" id="5_a0a5b"]
|
||||||
[ext_resource type="Animation" uid="uid://d1xnpyc08njjx" path="res://addons/godot-xr-tools/hands/animations/right/Grip 4.res" id="6_bdp75"]
|
[ext_resource type="Animation" uid="uid://d1xnpyc08njjx" path="res://addons/godot-xr-tools/hands/animations/right/Grip 4.res" id="6_bdp75"]
|
||||||
[ext_resource type="PackedScene" uid="uid://3lr2dhy62rhk" path="res://Prefabs/combinable_item.tscn" id="7_bdp75"]
|
[ext_resource type="PackedScene" uid="uid://3lr2dhy62rhk" path="res://Prefabs/combinable_item.tscn" id="7_bdp75"]
|
||||||
[ext_resource type="PackedScene" uid="uid://b5ukku8i0hilb" path="res://Prefabs/despawning_item.tscn" id="10_uygc5"]
|
[ext_resource type="PackedScene" uid="uid://cucc3gaqu2nab" path="res://Items/Charcoal.tscn" id="8_a0a5b"]
|
||||||
|
[ext_resource type="PackedScene" uid="uid://7earnjgdmwgx" path="res://Prefabs/cookable_item.tscn" id="10_65ccv"]
|
||||||
|
[ext_resource type="Script" uid="uid://coidnv8b2yvxr" path="res://Prefabs/combine_recipe.gd" id="11_recipe"]
|
||||||
[ext_resource type="PackedScene" uid="uid://bfj80jh13t6e5" path="res://Prefabs/food_item.tscn" id="11_vjw41"]
|
[ext_resource type="PackedScene" uid="uid://bfj80jh13t6e5" path="res://Prefabs/food_item.tscn" id="11_vjw41"]
|
||||||
[ext_resource type="Script" uid="uid://bwd0pe2udb5xo" path="res://Net/net_pickable.gd" id="20_netpk"]
|
[ext_resource type="Script" path="res://Prefabs/net_pickable.gd" id="12_net"]
|
||||||
|
|
||||||
|
[sub_resource type="SceneReplicationConfig" id="Repl_item"]
|
||||||
|
properties/0/path = NodePath(".:global_transform")
|
||||||
|
properties/0/spawn = true
|
||||||
|
properties/0/replication_mode = 1
|
||||||
|
|
||||||
[sub_resource type="BoxShape3D" id="BoxShape3D_m1xbq"]
|
[sub_resource type="BoxShape3D" id="BoxShape3D_m1xbq"]
|
||||||
size = Vector3(0.1, 0.1, 0.1)
|
size = Vector3(0.1, 0.1, 0.1)
|
||||||
@@ -31,16 +38,11 @@ script = ExtResource("4_hc3f7")
|
|||||||
closed_pose = ExtResource("6_bdp75")
|
closed_pose = ExtResource("6_bdp75")
|
||||||
metadata/_custom_type_script = "uid://dvobm6vcfnqe8"
|
metadata/_custom_type_script = "uid://dvobm6vcfnqe8"
|
||||||
|
|
||||||
[sub_resource type="SceneReplicationConfig" id="SceneReplicationConfig_np_cube"]
|
[sub_resource type="Resource" id="Resource_i8ixk"]
|
||||||
properties/0/path = NodePath(".:position")
|
script = ExtResource("11_recipe")
|
||||||
properties/0/spawn = false
|
ingredient_id = &"cube"
|
||||||
properties/0/replication_mode = 1
|
result = ExtResource("8_a0a5b")
|
||||||
properties/1/path = NodePath(".:quaternion")
|
metadata/_custom_type_script = "uid://coidnv8b2yvxr"
|
||||||
properties/1/spawn = false
|
|
||||||
properties/1/replication_mode = 1
|
|
||||||
properties/2/path = NodePath("NetPickable:net_held_by")
|
|
||||||
properties/2/spawn = true
|
|
||||||
properties/2/replication_mode = 1
|
|
||||||
|
|
||||||
[node name="PickableObject" unique_id=1675596942 groups=["platalbe_item"] instance=ExtResource("1_dbtw8")]
|
[node name="PickableObject" unique_id=1675596942 groups=["platalbe_item"] instance=ExtResource("1_dbtw8")]
|
||||||
|
|
||||||
@@ -58,14 +60,18 @@ hand_pose = SubResource("Resource_lc22d")
|
|||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.06531982, 0.042291984, -0.08604182)
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.06531982, 0.042291984, -0.08604182)
|
||||||
hand_pose = SubResource("Resource_qyiot")
|
hand_pose = SubResource("Resource_qyiot")
|
||||||
|
|
||||||
[node name="FoodItem" parent="." index="4" unique_id=63948206 instance=ExtResource("11_vjw41")]
|
[node name="CombinableItem" parent="." index="4" unique_id=996936271 instance=ExtResource("7_bdp75")]
|
||||||
|
id = &"cube"
|
||||||
|
recipes = Array[ExtResource("11_recipe")]([SubResource("Resource_i8ixk")])
|
||||||
|
|
||||||
|
[node name="CookableItem" parent="." index="5" unique_id=280820828 instance=ExtResource("10_65ccv")]
|
||||||
|
|
||||||
|
[node name="FoodItem" parent="." index="6" unique_id=63948206 instance=ExtResource("11_vjw41")]
|
||||||
id = "cube"
|
id = "cube"
|
||||||
type = 1
|
type = 1
|
||||||
|
|
||||||
[node name="CombinableItem" parent="." index="5" unique_id=996936271 instance=ExtResource("7_bdp75")]
|
[node name="NetPickable" type="Node" parent="." index="7"]
|
||||||
|
script = ExtResource("12_net")
|
||||||
|
|
||||||
[node name="NetPickable" type="MultiplayerSynchronizer" parent="." index="6" unique_id=1858332513]
|
[node name="MultiplayerSynchronizer" type="MultiplayerSynchronizer" parent="." index="8"]
|
||||||
replication_config = SubResource("SceneReplicationConfig_np_cube")
|
replication_config = SubResource("Repl_item")
|
||||||
script = ExtResource("20_netpk")
|
|
||||||
|
|
||||||
[node name="DespawningItem" parent="." index="7" unique_id=303090111 instance=ExtResource("10_uygc5")]
|
|
||||||
|
|||||||
+15
-22
@@ -7,9 +7,14 @@
|
|||||||
[ext_resource type="Script" uid="uid://dvobm6vcfnqe8" path="res://addons/godot-xr-tools/hands/poses/hand_pose_settings.gd" id="5_w8sii"]
|
[ext_resource type="Script" uid="uid://dvobm6vcfnqe8" path="res://addons/godot-xr-tools/hands/poses/hand_pose_settings.gd" id="5_w8sii"]
|
||||||
[ext_resource type="PackedScene" uid="uid://ctw7nbntd5pcj" path="res://addons/godot-xr-tools/objects/grab_points/grab_point_hand_right.tscn" id="6_mvnl5"]
|
[ext_resource type="PackedScene" uid="uid://ctw7nbntd5pcj" path="res://addons/godot-xr-tools/objects/grab_points/grab_point_hand_right.tscn" id="6_mvnl5"]
|
||||||
[ext_resource type="Animation" uid="uid://d1xnpyc08njjx" path="res://addons/godot-xr-tools/hands/animations/right/Grip 4.res" id="7_wqxjj"]
|
[ext_resource type="Animation" uid="uid://d1xnpyc08njjx" path="res://addons/godot-xr-tools/hands/animations/right/Grip 4.res" id="7_wqxjj"]
|
||||||
[ext_resource type="PackedScene" uid="uid://b5ukku8i0hilb" path="res://Prefabs/despawning_item.tscn" id="10_l4hsd"]
|
[ext_resource type="PackedScene" uid="uid://7earnjgdmwgx" path="res://Prefabs/cookable_item.tscn" id="9_hwyyd"]
|
||||||
[ext_resource type="PackedScene" uid="uid://bfj80jh13t6e5" path="res://Prefabs/food_item.tscn" id="10_yxtxs"]
|
[ext_resource type="PackedScene" uid="uid://cfc4ho67u4r5e" path="res://Items/cooked_burger.tscn" id="9_r8jvx"]
|
||||||
[ext_resource type="Script" uid="uid://bwd0pe2udb5xo" path="res://Net/net_pickable.gd" id="20_netpk"]
|
[ext_resource type="Script" path="res://Prefabs/net_pickable.gd" id="12_net"]
|
||||||
|
|
||||||
|
[sub_resource type="SceneReplicationConfig" id="Repl_item"]
|
||||||
|
properties/0/path = NodePath(".:global_transform")
|
||||||
|
properties/0/spawn = true
|
||||||
|
properties/0/replication_mode = 1
|
||||||
|
|
||||||
[sub_resource type="CylinderShape3D" id="CylinderShape3D_fco8w"]
|
[sub_resource type="CylinderShape3D" id="CylinderShape3D_fco8w"]
|
||||||
height = 0.0338974
|
height = 0.0338974
|
||||||
@@ -28,18 +33,7 @@ script = ExtResource("5_w8sii")
|
|||||||
closed_pose = ExtResource("7_wqxjj")
|
closed_pose = ExtResource("7_wqxjj")
|
||||||
metadata/_custom_type_script = "uid://dvobm6vcfnqe8"
|
metadata/_custom_type_script = "uid://dvobm6vcfnqe8"
|
||||||
|
|
||||||
[sub_resource type="SceneReplicationConfig" id="SceneReplicationConfig_np_burger"]
|
[node name="burger" unique_id=1675596942 instance=ExtResource("1_fco8w")]
|
||||||
properties/0/path = NodePath(".:position")
|
|
||||||
properties/0/spawn = false
|
|
||||||
properties/0/replication_mode = 1
|
|
||||||
properties/1/path = NodePath(".:quaternion")
|
|
||||||
properties/1/spawn = false
|
|
||||||
properties/1/replication_mode = 1
|
|
||||||
properties/2/path = NodePath("NetPickable:net_held_by")
|
|
||||||
properties/2/spawn = true
|
|
||||||
properties/2/replication_mode = 1
|
|
||||||
|
|
||||||
[node name="raw_burger" unique_id=1675596942 instance=ExtResource("1_fco8w")]
|
|
||||||
|
|
||||||
[node name="CollisionShape3D" parent="." index="0"]
|
[node name="CollisionShape3D" parent="." index="0"]
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.00077831745, 0)
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.00077831745, 0)
|
||||||
@@ -59,12 +53,11 @@ hand_pose = SubResource("Resource_lc22d")
|
|||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.06531982, 0.042291984, -0.08604182)
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.06531982, 0.042291984, -0.08604182)
|
||||||
hand_pose = SubResource("Resource_qyiot")
|
hand_pose = SubResource("Resource_qyiot")
|
||||||
|
|
||||||
[node name="FoodItem" parent="." index="4" unique_id=63948206 instance=ExtResource("10_yxtxs")]
|
[node name="CookableItem" parent="." index="4" unique_id=280820828 instance=ExtResource("9_hwyyd")]
|
||||||
id = "raw_burger"
|
turns_into = ExtResource("9_r8jvx")
|
||||||
type = 2
|
|
||||||
|
|
||||||
[node name="NetPickable" type="MultiplayerSynchronizer" parent="." index="5" unique_id=1382968688]
|
[node name="NetPickable" type="Node" parent="." index="5"]
|
||||||
replication_config = SubResource("SceneReplicationConfig_np_burger")
|
script = ExtResource("12_net")
|
||||||
script = ExtResource("20_netpk")
|
|
||||||
|
|
||||||
[node name="DespawningItem" parent="." index="6" unique_id=303090111 instance=ExtResource("10_l4hsd")]
|
[node name="MultiplayerSynchronizer" type="MultiplayerSynchronizer" parent="." index="6"]
|
||||||
|
replication_config = SubResource("Repl_item")
|
||||||
|
|||||||
+11
-23
@@ -6,10 +6,10 @@
|
|||||||
[ext_resource type="Script" uid="uid://dvobm6vcfnqe8" path="res://addons/godot-xr-tools/hands/poses/hand_pose_settings.gd" id="5_ychvb"]
|
[ext_resource type="Script" uid="uid://dvobm6vcfnqe8" path="res://addons/godot-xr-tools/hands/poses/hand_pose_settings.gd" id="5_ychvb"]
|
||||||
[ext_resource type="PackedScene" uid="uid://ctw7nbntd5pcj" path="res://addons/godot-xr-tools/objects/grab_points/grab_point_hand_right.tscn" id="6_etdv2"]
|
[ext_resource type="PackedScene" uid="uid://ctw7nbntd5pcj" path="res://addons/godot-xr-tools/objects/grab_points/grab_point_hand_right.tscn" id="6_etdv2"]
|
||||||
[ext_resource type="Animation" uid="uid://d1xnpyc08njjx" path="res://addons/godot-xr-tools/hands/animations/right/Grip 4.res" id="7_rl64h"]
|
[ext_resource type="Animation" uid="uid://d1xnpyc08njjx" path="res://addons/godot-xr-tools/hands/animations/right/Grip 4.res" id="7_rl64h"]
|
||||||
[ext_resource type="PackedScene" uid="uid://b5ukku8i0hilb" path="res://Prefabs/despawning_item.tscn" id="10_6p8pj"]
|
|
||||||
[ext_resource type="PackedScene" uid="uid://3lr2dhy62rhk" path="res://Prefabs/combinable_item.tscn" id="10_ut7mg"]
|
[ext_resource type="PackedScene" uid="uid://3lr2dhy62rhk" path="res://Prefabs/combinable_item.tscn" id="10_ut7mg"]
|
||||||
[ext_resource type="PackedScene" uid="uid://bfj80jh13t6e5" path="res://Prefabs/food_item.tscn" id="10_zz42p"]
|
[ext_resource type="PackedScene" uid="uid://7earnjgdmwgx" path="res://Prefabs/cookable_item.tscn" id="11_5ch2b"]
|
||||||
[ext_resource type="Script" uid="uid://bwd0pe2udb5xo" path="res://Net/net_pickable.gd" id="20_netpk"]
|
[ext_resource type="Script" uid="uid://coidnv8b2yvxr" path="res://Prefabs/combine_recipe.gd" id="11_rjayc"]
|
||||||
|
[ext_resource type="PackedScene" uid="uid://b3m2ag8g5rj4r" path="res://Items/hamburger.tscn" id="11_ut7mg"]
|
||||||
|
|
||||||
[sub_resource type="CylinderShape3D" id="CylinderShape3D_fco8w"]
|
[sub_resource type="CylinderShape3D" id="CylinderShape3D_fco8w"]
|
||||||
height = 0.04777527
|
height = 0.04777527
|
||||||
@@ -28,16 +28,11 @@ script = ExtResource("5_ychvb")
|
|||||||
closed_pose = ExtResource("7_rl64h")
|
closed_pose = ExtResource("7_rl64h")
|
||||||
metadata/_custom_type_script = "uid://dvobm6vcfnqe8"
|
metadata/_custom_type_script = "uid://dvobm6vcfnqe8"
|
||||||
|
|
||||||
[sub_resource type="SceneReplicationConfig" id="SceneReplicationConfig_np_cookedburger"]
|
[sub_resource type="Resource" id="Resource_wi1yl"]
|
||||||
properties/0/path = NodePath(".:position")
|
script = ExtResource("11_rjayc")
|
||||||
properties/0/spawn = false
|
ingredient_id = &"burger_buns"
|
||||||
properties/0/replication_mode = 1
|
result = ExtResource("11_ut7mg")
|
||||||
properties/1/path = NodePath(".:quaternion")
|
metadata/_custom_type_script = "uid://coidnv8b2yvxr"
|
||||||
properties/1/spawn = false
|
|
||||||
properties/1/replication_mode = 1
|
|
||||||
properties/2/path = NodePath("NetPickable:net_held_by")
|
|
||||||
properties/2/spawn = true
|
|
||||||
properties/2/replication_mode = 1
|
|
||||||
|
|
||||||
[node name="CookedBurger" unique_id=1675596942 instance=ExtResource("1_ut7mg")]
|
[node name="CookedBurger" unique_id=1675596942 instance=ExtResource("1_ut7mg")]
|
||||||
|
|
||||||
@@ -59,14 +54,7 @@ hand_pose = SubResource("Resource_lc22d")
|
|||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.06531982, 0.042291984, -0.08604182)
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.06531982, 0.042291984, -0.08604182)
|
||||||
hand_pose = SubResource("Resource_qyiot")
|
hand_pose = SubResource("Resource_qyiot")
|
||||||
|
|
||||||
[node name="FoodItem" parent="." index="4" unique_id=234567891 instance=ExtResource("10_zz42p")]
|
[node name="CombinableItem" parent="." index="4" unique_id=434304805 instance=ExtResource("10_ut7mg")]
|
||||||
id = "cooked_burger"
|
recipes = Array[ExtResource("11_rjayc")]([SubResource("Resource_wi1yl")])
|
||||||
type = 2
|
|
||||||
|
|
||||||
[node name="CombinableItem" parent="." index="5" unique_id=996936271 instance=ExtResource("10_ut7mg")]
|
[node name="CookableItem" parent="." index="5" unique_id=280820828 instance=ExtResource("11_5ch2b")]
|
||||||
|
|
||||||
[node name="NetPickable" type="MultiplayerSynchronizer" parent="." index="6" unique_id=925955029]
|
|
||||||
replication_config = SubResource("SceneReplicationConfig_np_cookedburger")
|
|
||||||
script = ExtResource("20_netpk")
|
|
||||||
|
|
||||||
[node name="DespawningItem" parent="." index="7" unique_id=303090111 instance=ExtResource("10_6p8pj")]
|
|
||||||
|
|||||||
+1
-22
@@ -7,8 +7,6 @@
|
|||||||
[ext_resource type="PackedScene" uid="uid://ctw7nbntd5pcj" path="res://addons/godot-xr-tools/objects/grab_points/grab_point_hand_right.tscn" id="5_dunns"]
|
[ext_resource type="PackedScene" uid="uid://ctw7nbntd5pcj" path="res://addons/godot-xr-tools/objects/grab_points/grab_point_hand_right.tscn" id="5_dunns"]
|
||||||
[ext_resource type="Animation" uid="uid://d1xnpyc08njjx" path="res://addons/godot-xr-tools/hands/animations/right/Grip 4.res" id="6_fh0f6"]
|
[ext_resource type="Animation" uid="uid://d1xnpyc08njjx" path="res://addons/godot-xr-tools/hands/animations/right/Grip 4.res" id="6_fh0f6"]
|
||||||
[ext_resource type="PackedScene" uid="uid://bfj80jh13t6e5" path="res://Prefabs/food_item.tscn" id="7_yy3y8"]
|
[ext_resource type="PackedScene" uid="uid://bfj80jh13t6e5" path="res://Prefabs/food_item.tscn" id="7_yy3y8"]
|
||||||
[ext_resource type="PackedScene" uid="uid://b5ukku8i0hilb" path="res://Prefabs/despawning_item.tscn" id="9_ej8jm"]
|
|
||||||
[ext_resource type="Script" uid="uid://bwd0pe2udb5xo" path="res://Net/net_pickable.gd" id="20_netpk"]
|
|
||||||
|
|
||||||
[sub_resource type="CylinderShape3D" id="CylinderShape3D_fco8w"]
|
[sub_resource type="CylinderShape3D" id="CylinderShape3D_fco8w"]
|
||||||
height = 0.10392761
|
height = 0.10392761
|
||||||
@@ -30,19 +28,8 @@ albedo_color = Color(0.6784191, 0.54546416, 0.016760282, 1)
|
|||||||
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_6l01i"]
|
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_6l01i"]
|
||||||
albedo_color = Color(0.29, 0.101500005, 0, 1)
|
albedo_color = Color(0.29, 0.101500005, 0, 1)
|
||||||
|
|
||||||
[sub_resource type="SceneReplicationConfig" id="SceneReplicationConfig_np_hamburger"]
|
|
||||||
properties/0/path = NodePath(".:position")
|
|
||||||
properties/0/spawn = false
|
|
||||||
properties/0/replication_mode = 1
|
|
||||||
properties/1/path = NodePath(".:quaternion")
|
|
||||||
properties/1/spawn = false
|
|
||||||
properties/1/replication_mode = 1
|
|
||||||
properties/2/path = NodePath("NetPickable:net_held_by")
|
|
||||||
properties/2/spawn = true
|
|
||||||
properties/2/replication_mode = 1
|
|
||||||
|
|
||||||
[node name="Hamburger" unique_id=1675596942 groups=["platalbe_item"] instance=ExtResource("1_3gf3l")]
|
[node name="Hamburger" unique_id=1675596942 groups=["platalbe_item"] instance=ExtResource("1_3gf3l")]
|
||||||
gravity_scale = 0.04
|
gravity_scale = 0.4
|
||||||
|
|
||||||
[node name="CollisionShape3D" parent="." index="0"]
|
[node name="CollisionShape3D" parent="." index="0"]
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.02, 0.02, 0)
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.02, 0.02, 0)
|
||||||
@@ -91,12 +78,4 @@ sides = 16
|
|||||||
material = SubResource("StandardMaterial3D_6l01i")
|
material = SubResource("StandardMaterial3D_6l01i")
|
||||||
|
|
||||||
[node name="FoodItem" parent="." index="5" unique_id=63948206 instance=ExtResource("7_yy3y8")]
|
[node name="FoodItem" parent="." index="5" unique_id=63948206 instance=ExtResource("7_yy3y8")]
|
||||||
id = "hamburger"
|
|
||||||
type = 0
|
type = 0
|
||||||
sell_value = 4
|
|
||||||
|
|
||||||
[node name="NetPickable" type="MultiplayerSynchronizer" parent="." index="6" unique_id=56164120]
|
|
||||||
replication_config = SubResource("SceneReplicationConfig_np_hamburger")
|
|
||||||
script = ExtResource("20_netpk")
|
|
||||||
|
|
||||||
[node name="DespawningItem" parent="." index="7" unique_id=303090111 instance=ExtResource("9_ej8jm")]
|
|
||||||
|
|||||||
@@ -0,0 +1,49 @@
|
|||||||
|
extends Control
|
||||||
|
|
||||||
|
## The 2D UI rendered inside the world-space menu (XRToolsViewport2DIn3D).
|
||||||
|
## Lets the player type an IP on a numeric keypad and pick Host / Join / Solo.
|
||||||
|
## Pure UI: it emits intents; main.gd performs the networking.
|
||||||
|
|
||||||
|
signal host_pressed()
|
||||||
|
signal join_pressed(ip: String)
|
||||||
|
signal solo_pressed()
|
||||||
|
|
||||||
|
#var _ip := "127.0.0.1"
|
||||||
|
var _ip := "51.175.10.161"
|
||||||
|
|
||||||
|
@onready var _ip_label: Label = %IPLabel
|
||||||
|
@onready var _status: Label = %Status
|
||||||
|
@onready var _keypad: GridContainer = %Keypad
|
||||||
|
@onready var _host_btn: Button = %HostButton
|
||||||
|
@onready var _join_btn: Button = %JoinButton
|
||||||
|
@onready var _solo_btn: Button = %SoloButton
|
||||||
|
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
for child in _keypad.get_children():
|
||||||
|
if child is Button:
|
||||||
|
child.pressed.connect(_on_key.bind(child.text))
|
||||||
|
_host_btn.pressed.connect(func(): host_pressed.emit())
|
||||||
|
_join_btn.pressed.connect(func(): join_pressed.emit(_ip))
|
||||||
|
_solo_btn.pressed.connect(func(): solo_pressed.emit())
|
||||||
|
_refresh()
|
||||||
|
|
||||||
|
|
||||||
|
func _on_key(key: String) -> void:
|
||||||
|
match key:
|
||||||
|
"DEL":
|
||||||
|
_ip = _ip.substr(0, max(0, _ip.length() - 1))
|
||||||
|
_:
|
||||||
|
if _ip.length() < 21:
|
||||||
|
_ip += key
|
||||||
|
_refresh()
|
||||||
|
|
||||||
|
|
||||||
|
func _refresh() -> void:
|
||||||
|
_ip_label.text = _ip if not _ip.is_empty() else "_"
|
||||||
|
|
||||||
|
|
||||||
|
## Called by main.gd (via network_menu) to show connection feedback.
|
||||||
|
func set_status(text: String) -> void:
|
||||||
|
if _status:
|
||||||
|
_status.text = text
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://dvivyrspjcjgm
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
[gd_scene load_steps=2 format=3]
|
[gd_scene load_steps=2 format=3]
|
||||||
|
|
||||||
[ext_resource type="Script" path="res://UI/main_menu_panel.gd" id="1_panel"]
|
[ext_resource type="Script" path="res://Net/join_panel.gd" id="1_panel"]
|
||||||
|
|
||||||
[node name="MainMenuPanel" type="Control"]
|
[node name="JoinPanel" type="Control"]
|
||||||
layout_mode = 3
|
layout_mode = 3
|
||||||
anchors_preset = 15
|
anchors_preset = 15
|
||||||
anchor_right = 1.0
|
anchor_right = 1.0
|
||||||
@@ -26,72 +26,32 @@ theme_override_constants/margin_top = 16
|
|||||||
theme_override_constants/margin_right = 24
|
theme_override_constants/margin_right = 24
|
||||||
theme_override_constants/margin_bottom = 16
|
theme_override_constants/margin_bottom = 16
|
||||||
|
|
||||||
[node name="Title" type="Label" parent="Margin"]
|
[node name="VBox" type="VBoxContainer" parent="Margin"]
|
||||||
layout_mode = 2
|
|
||||||
size_flags_vertical = 0
|
|
||||||
theme_override_font_sizes/font_size = 26
|
|
||||||
text = "VRyHungry"
|
|
||||||
horizontal_alignment = 1
|
|
||||||
|
|
||||||
[node name="Status" type="Label" parent="Margin"]
|
|
||||||
unique_name_in_owner = true
|
|
||||||
layout_mode = 2
|
|
||||||
size_flags_vertical = 0
|
|
||||||
theme_override_colors/font_color = Color(0.8, 0.8, 0.5, 1)
|
|
||||||
theme_override_font_sizes/font_size = 16
|
|
||||||
text = ""
|
|
||||||
horizontal_alignment = 1
|
|
||||||
|
|
||||||
[node name="RootView" type="VBoxContainer" parent="Margin"]
|
|
||||||
unique_name_in_owner = true
|
|
||||||
layout_mode = 2
|
|
||||||
theme_override_constants/separation = 14
|
|
||||||
|
|
||||||
[node name="Spacer" type="Control" parent="Margin/RootView"]
|
|
||||||
custom_minimum_size = Vector2(0, 36)
|
|
||||||
layout_mode = 2
|
|
||||||
|
|
||||||
[node name="JohnButton" type="Button" parent="Margin/RootView"]
|
|
||||||
unique_name_in_owner = true
|
|
||||||
layout_mode = 2
|
|
||||||
custom_minimum_size = Vector2(0, 64)
|
|
||||||
theme_override_font_sizes/font_size = 26
|
|
||||||
text = "Play John's Scene"
|
|
||||||
|
|
||||||
[node name="HostButton" type="Button" parent="Margin/RootView"]
|
|
||||||
unique_name_in_owner = true
|
|
||||||
layout_mode = 2
|
|
||||||
custom_minimum_size = Vector2(0, 64)
|
|
||||||
theme_override_font_sizes/font_size = 26
|
|
||||||
text = "Host Multiplayer"
|
|
||||||
|
|
||||||
[node name="JoinMenuButton" type="Button" parent="Margin/RootView"]
|
|
||||||
unique_name_in_owner = true
|
|
||||||
layout_mode = 2
|
|
||||||
custom_minimum_size = Vector2(0, 64)
|
|
||||||
theme_override_font_sizes/font_size = 26
|
|
||||||
text = "Join Multiplayer"
|
|
||||||
|
|
||||||
[node name="JoinView" type="VBoxContainer" parent="Margin"]
|
|
||||||
unique_name_in_owner = true
|
|
||||||
visible = false
|
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
theme_override_constants/separation = 10
|
theme_override_constants/separation = 10
|
||||||
|
|
||||||
[node name="Title" type="Label" parent="Margin/JoinView"]
|
[node name="Title" type="Label" parent="Margin/VBox"]
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
theme_override_font_sizes/font_size = 22
|
theme_override_font_sizes/font_size = 26
|
||||||
text = "Join Multiplayer"
|
text = "VRyHungry — Multiplayer"
|
||||||
horizontal_alignment = 1
|
horizontal_alignment = 1
|
||||||
|
|
||||||
[node name="IPLabel" type="Label" parent="Margin/JoinView"]
|
[node name="IPLabel" type="Label" parent="Margin/VBox"]
|
||||||
unique_name_in_owner = true
|
unique_name_in_owner = true
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
theme_override_font_sizes/font_size = 34
|
theme_override_font_sizes/font_size = 34
|
||||||
text = "127.0.0.1"
|
text = "127.0.0.1"
|
||||||
horizontal_alignment = 1
|
horizontal_alignment = 1
|
||||||
|
|
||||||
[node name="Keypad" type="GridContainer" parent="Margin/JoinView"]
|
[node name="Status" type="Label" parent="Margin/VBox"]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
layout_mode = 2
|
||||||
|
theme_override_colors/font_color = Color(0.8, 0.8, 0.5, 1)
|
||||||
|
theme_override_font_sizes/font_size = 18
|
||||||
|
text = "Enter host IP, then Join"
|
||||||
|
horizontal_alignment = 1
|
||||||
|
|
||||||
|
[node name="Keypad" type="GridContainer" parent="Margin/VBox"]
|
||||||
unique_name_in_owner = true
|
unique_name_in_owner = true
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
size_flags_vertical = 3
|
size_flags_vertical = 3
|
||||||
@@ -99,95 +59,103 @@ theme_override_constants/h_separation = 8
|
|||||||
theme_override_constants/v_separation = 8
|
theme_override_constants/v_separation = 8
|
||||||
columns = 3
|
columns = 3
|
||||||
|
|
||||||
[node name="B1" type="Button" parent="Margin/JoinView/Keypad"]
|
[node name="B1" type="Button" parent="Margin/VBox/Keypad"]
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
size_flags_horizontal = 3
|
size_flags_horizontal = 3
|
||||||
size_flags_vertical = 3
|
size_flags_vertical = 3
|
||||||
theme_override_font_sizes/font_size = 26
|
theme_override_font_sizes/font_size = 26
|
||||||
text = "1"
|
text = "1"
|
||||||
|
|
||||||
[node name="B2" type="Button" parent="Margin/JoinView/Keypad"]
|
[node name="B2" type="Button" parent="Margin/VBox/Keypad"]
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
size_flags_horizontal = 3
|
size_flags_horizontal = 3
|
||||||
size_flags_vertical = 3
|
size_flags_vertical = 3
|
||||||
theme_override_font_sizes/font_size = 26
|
theme_override_font_sizes/font_size = 26
|
||||||
text = "2"
|
text = "2"
|
||||||
|
|
||||||
[node name="B3" type="Button" parent="Margin/JoinView/Keypad"]
|
[node name="B3" type="Button" parent="Margin/VBox/Keypad"]
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
size_flags_horizontal = 3
|
size_flags_horizontal = 3
|
||||||
size_flags_vertical = 3
|
size_flags_vertical = 3
|
||||||
theme_override_font_sizes/font_size = 26
|
theme_override_font_sizes/font_size = 26
|
||||||
text = "3"
|
text = "3"
|
||||||
|
|
||||||
[node name="B4" type="Button" parent="Margin/JoinView/Keypad"]
|
[node name="B4" type="Button" parent="Margin/VBox/Keypad"]
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
size_flags_horizontal = 3
|
size_flags_horizontal = 3
|
||||||
size_flags_vertical = 3
|
size_flags_vertical = 3
|
||||||
theme_override_font_sizes/font_size = 26
|
theme_override_font_sizes/font_size = 26
|
||||||
text = "4"
|
text = "4"
|
||||||
|
|
||||||
[node name="B5" type="Button" parent="Margin/JoinView/Keypad"]
|
[node name="B5" type="Button" parent="Margin/VBox/Keypad"]
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
size_flags_horizontal = 3
|
size_flags_horizontal = 3
|
||||||
size_flags_vertical = 3
|
size_flags_vertical = 3
|
||||||
theme_override_font_sizes/font_size = 26
|
theme_override_font_sizes/font_size = 26
|
||||||
text = "5"
|
text = "5"
|
||||||
|
|
||||||
[node name="B6" type="Button" parent="Margin/JoinView/Keypad"]
|
[node name="B6" type="Button" parent="Margin/VBox/Keypad"]
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
size_flags_horizontal = 3
|
size_flags_horizontal = 3
|
||||||
size_flags_vertical = 3
|
size_flags_vertical = 3
|
||||||
theme_override_font_sizes/font_size = 26
|
theme_override_font_sizes/font_size = 26
|
||||||
text = "6"
|
text = "6"
|
||||||
|
|
||||||
[node name="B7" type="Button" parent="Margin/JoinView/Keypad"]
|
[node name="B7" type="Button" parent="Margin/VBox/Keypad"]
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
size_flags_horizontal = 3
|
size_flags_horizontal = 3
|
||||||
size_flags_vertical = 3
|
size_flags_vertical = 3
|
||||||
theme_override_font_sizes/font_size = 26
|
theme_override_font_sizes/font_size = 26
|
||||||
text = "7"
|
text = "7"
|
||||||
|
|
||||||
[node name="B8" type="Button" parent="Margin/JoinView/Keypad"]
|
[node name="B8" type="Button" parent="Margin/VBox/Keypad"]
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
size_flags_horizontal = 3
|
size_flags_horizontal = 3
|
||||||
size_flags_vertical = 3
|
size_flags_vertical = 3
|
||||||
theme_override_font_sizes/font_size = 26
|
theme_override_font_sizes/font_size = 26
|
||||||
text = "8"
|
text = "8"
|
||||||
|
|
||||||
[node name="B9" type="Button" parent="Margin/JoinView/Keypad"]
|
[node name="B9" type="Button" parent="Margin/VBox/Keypad"]
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
size_flags_horizontal = 3
|
size_flags_horizontal = 3
|
||||||
size_flags_vertical = 3
|
size_flags_vertical = 3
|
||||||
theme_override_font_sizes/font_size = 26
|
theme_override_font_sizes/font_size = 26
|
||||||
text = "9"
|
text = "9"
|
||||||
|
|
||||||
[node name="BDot" type="Button" parent="Margin/JoinView/Keypad"]
|
[node name="BDot" type="Button" parent="Margin/VBox/Keypad"]
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
size_flags_horizontal = 3
|
size_flags_horizontal = 3
|
||||||
size_flags_vertical = 3
|
size_flags_vertical = 3
|
||||||
theme_override_font_sizes/font_size = 26
|
theme_override_font_sizes/font_size = 26
|
||||||
text = "."
|
text = "."
|
||||||
|
|
||||||
[node name="B0" type="Button" parent="Margin/JoinView/Keypad"]
|
[node name="B0" type="Button" parent="Margin/VBox/Keypad"]
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
size_flags_horizontal = 3
|
size_flags_horizontal = 3
|
||||||
size_flags_vertical = 3
|
size_flags_vertical = 3
|
||||||
theme_override_font_sizes/font_size = 26
|
theme_override_font_sizes/font_size = 26
|
||||||
text = "0"
|
text = "0"
|
||||||
|
|
||||||
[node name="BDel" type="Button" parent="Margin/JoinView/Keypad"]
|
[node name="BDel" type="Button" parent="Margin/VBox/Keypad"]
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
size_flags_horizontal = 3
|
size_flags_horizontal = 3
|
||||||
size_flags_vertical = 3
|
size_flags_vertical = 3
|
||||||
theme_override_font_sizes/font_size = 22
|
theme_override_font_sizes/font_size = 22
|
||||||
text = "DEL"
|
text = "DEL"
|
||||||
|
|
||||||
[node name="Buttons" type="HBoxContainer" parent="Margin/JoinView"]
|
[node name="Buttons" type="HBoxContainer" parent="Margin/VBox"]
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
theme_override_constants/separation = 10
|
theme_override_constants/separation = 10
|
||||||
|
|
||||||
[node name="JoinButton" type="Button" parent="Margin/JoinView/Buttons"]
|
[node name="HostButton" type="Button" parent="Margin/VBox/Buttons"]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_horizontal = 3
|
||||||
|
custom_minimum_size = Vector2(0, 56)
|
||||||
|
theme_override_font_sizes/font_size = 24
|
||||||
|
text = "HOST"
|
||||||
|
|
||||||
|
[node name="JoinButton" type="Button" parent="Margin/VBox/Buttons"]
|
||||||
unique_name_in_owner = true
|
unique_name_in_owner = true
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
size_flags_horizontal = 3
|
size_flags_horizontal = 3
|
||||||
@@ -195,10 +163,10 @@ custom_minimum_size = Vector2(0, 56)
|
|||||||
theme_override_font_sizes/font_size = 24
|
theme_override_font_sizes/font_size = 24
|
||||||
text = "JOIN"
|
text = "JOIN"
|
||||||
|
|
||||||
[node name="BackButton" type="Button" parent="Margin/JoinView/Buttons"]
|
[node name="SoloButton" type="Button" parent="Margin/VBox/Buttons"]
|
||||||
unique_name_in_owner = true
|
unique_name_in_owner = true
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
size_flags_horizontal = 3
|
size_flags_horizontal = 3
|
||||||
custom_minimum_size = Vector2(0, 56)
|
custom_minimum_size = Vector2(0, 56)
|
||||||
theme_override_font_sizes/font_size = 24
|
theme_override_font_sizes/font_size = 24
|
||||||
text = "BACK"
|
text = "SOLO"
|
||||||
@@ -1,209 +0,0 @@
|
|||||||
extends MultiplayerSynchronizer
|
|
||||||
|
|
||||||
## Networked sync component for a pickable item. Added as a child literally
|
|
||||||
## named "NetPickable" (network_manager.gd's authority RPCs already expect
|
|
||||||
## this) of every net-synced pickable, replicating its transform and held
|
|
||||||
## state. Only the current multiplayer authority (the server while loose, or
|
|
||||||
## whichever peer is holding it) actually simulates physics for the item;
|
|
||||||
## every other peer freezes their local copy and just follows the synced
|
|
||||||
## transform.
|
|
||||||
|
|
||||||
## 0 = loose/server-simulated; otherwise the peer id currently holding it.
|
|
||||||
## Replicated at spawn and on change so a late joiner sees the current holder.
|
|
||||||
var net_held_by: int = 0: set = _set_net_held_by
|
|
||||||
|
|
||||||
var _pickable: XRToolsPickable
|
|
||||||
|
|
||||||
# This item's own baked freeze_mode (e.g. plate.tscn bakes KINEMATIC, not the
|
|
||||||
# RigidBody3D default of STATIC) — captured once so it can be restored when
|
|
||||||
# this peer regains ownership, instead of getting stuck on whatever
|
|
||||||
# apply_held_state() last forced it to while non-authority.
|
|
||||||
var _original_freeze_mode: int
|
|
||||||
|
|
||||||
# Same idea for the pickable's authored `enabled` flag, which the non-authority
|
|
||||||
# branch of apply_held_state() clears while someone else is holding the item.
|
|
||||||
var _original_enabled: bool
|
|
||||||
|
|
||||||
# Whether the "our own hand still holds this" guard has already been logged for
|
|
||||||
# the current grab. apply_held_state() runs every network tick, so without this
|
|
||||||
# the guard message repeats for as long as you hold the item.
|
|
||||||
var _grab_race_logged := false
|
|
||||||
|
|
||||||
|
|
||||||
func _ready() -> void:
|
|
||||||
_pickable = get_parent() as XRToolsPickable
|
|
||||||
if not _pickable:
|
|
||||||
push_error("NetPickable must be a child of an XRToolsPickable")
|
|
||||||
return
|
|
||||||
_original_freeze_mode = _pickable.freeze_mode
|
|
||||||
_original_enabled = _pickable.enabled
|
|
||||||
_pickable.picked_up.connect(_on_picked_up)
|
|
||||||
_pickable.dropped.connect(_on_dropped)
|
|
||||||
# Deferred: the pickable root captures its own original_collision_mask/
|
|
||||||
# original_collision_layer via @onready, which runs AFTER this child's
|
|
||||||
# _ready() but BEFORE the root's _ready() body. Calling apply_held_state
|
|
||||||
# synchronously here would freeze/mask the item before that capture runs,
|
|
||||||
# permanently corrupting the "restore on drop" values.
|
|
||||||
apply_held_state.call_deferred()
|
|
||||||
|
|
||||||
|
|
||||||
func _set_net_held_by(value: int) -> void:
|
|
||||||
var old := net_held_by
|
|
||||||
net_held_by = value
|
|
||||||
if old != value and NetworkManager.is_online():
|
|
||||||
print("%s net_held_by: %d -> %d (local state: %s, authority=%d)" % [
|
|
||||||
_pickable.name, old, value, _holder_desc(), get_multiplayer_authority()
|
|
||||||
])
|
|
||||||
apply_held_state()
|
|
||||||
|
|
||||||
|
|
||||||
## Puts the item in the right physics state for whether this peer currently
|
|
||||||
## owns it. Called locally after net_held_by changes, and directly by
|
|
||||||
## NetworkManager._set_item_authority right after an authority handoff.
|
|
||||||
##
|
|
||||||
## IMPORTANT: this runs on every network tick, not just on a real change.
|
|
||||||
## net_held_by is replicated in ALWAYS mode, so the synchronizer assigns it every
|
|
||||||
## tick on non-authority peers — unchanged value included — and that assignment
|
|
||||||
## lands in _set_net_held_by(), which calls this. So every branch here has to be
|
|
||||||
## idempotent and silent when there is nothing to do: otherwise each item logs a
|
|
||||||
## line and rewrites four physics properties every tick on every peer that
|
|
||||||
## doesn't own it.
|
|
||||||
func apply_held_state() -> void:
|
|
||||||
if not _pickable:
|
|
||||||
return
|
|
||||||
if not NetworkManager.is_online() or is_multiplayer_authority():
|
|
||||||
_grab_race_logged = false
|
|
||||||
# We own this item's simulation (offline, loose+server, or currently
|
|
||||||
# holding it). If it's not actively in our own hand right now, make
|
|
||||||
# sure it isn't still left frozen/collision-less from a previous
|
|
||||||
# non-authority period (e.g. right after regaining authority when a
|
|
||||||
# client released it) — while actually held, XRToolsPickable's own
|
|
||||||
# pick_up()/let_go() already manage these fields, so leave those be.
|
|
||||||
if not _pickable.is_picked_up():
|
|
||||||
var changed := _pickable.freeze_mode != _original_freeze_mode \
|
|
||||||
or _pickable.collision_mask != _pickable.original_collision_mask
|
|
||||||
if changed:
|
|
||||||
if NetworkManager.is_online():
|
|
||||||
print(
|
|
||||||
"%s: reclaiming ownership, restoring freeze_mode %d->%d collision_mask %d->%d" % [
|
|
||||||
_pickable.name, _pickable.freeze_mode, _original_freeze_mode,
|
|
||||||
_pickable.collision_mask, _pickable.original_collision_mask
|
|
||||||
]
|
|
||||||
)
|
|
||||||
_pickable.freeze_mode = _original_freeze_mode
|
|
||||||
_pickable.collision_mask = _pickable.original_collision_mask
|
|
||||||
# Unlike freeze/collision (which XRToolsPickable manages itself while
|
|
||||||
# held), `enabled` is only ever written by the non-authority branch
|
|
||||||
# below, so it must be restored here or it stays false forever: once a
|
|
||||||
# client grabbed this item, every other peer set enabled=false, and
|
|
||||||
# regaining authority left it that way. On the server that silently
|
|
||||||
# broke everything downstream — hands couldn't pick the item up again,
|
|
||||||
# and a station snap zone would "snap" it (emitting has_picked_up, so
|
|
||||||
# e.g. a plate still got marked dirty) while pick_up() bailed out on
|
|
||||||
# the disabled item, leaving the zone holding an item with no grab
|
|
||||||
# driver that then fell out of the station.
|
|
||||||
if _pickable.enabled != _original_enabled:
|
|
||||||
if NetworkManager.is_online():
|
|
||||||
print("%s: reclaiming ownership, restoring enabled %s->%s" % [
|
|
||||||
_pickable.name, _pickable.enabled, _original_enabled
|
|
||||||
])
|
|
||||||
_pickable.enabled = _original_enabled
|
|
||||||
return
|
|
||||||
# A net_held_by/position sync update can race ahead of the
|
|
||||||
# authority-handoff RPC that's about to confirm a grab we just made
|
|
||||||
# optimistically (they travel on different channels with no ordering
|
|
||||||
# guarantee). Don't let a stale sync value yank an item out of our own
|
|
||||||
# hand mid-grab — only an explicit force_release_item rejection, or
|
|
||||||
# actually losing authority for real, should end a grab we initiated.
|
|
||||||
if _pickable.is_picked_up() and _pickable.get_picked_up_by() is XRToolsFunctionPickup:
|
|
||||||
# Log once per grab, not once per tick.
|
|
||||||
if NetworkManager.is_online() and not _grab_race_logged:
|
|
||||||
_grab_race_logged = true
|
|
||||||
print(
|
|
||||||
"%s: ignoring non-authority sync (net_held_by=%d) — still actively held by our own hand (grab-race guard)" % [
|
|
||||||
_pickable.name, net_held_by
|
|
||||||
]
|
|
||||||
)
|
|
||||||
return
|
|
||||||
_grab_race_logged = false
|
|
||||||
# Someone else owns it: stop simulating locally, just follow the sync.
|
|
||||||
if _pickable.is_picked_up():
|
|
||||||
if NetworkManager.is_online():
|
|
||||||
print(
|
|
||||||
"%s: was held by %s on this peer, but authority now says peer %d owns it — force-dropping" % [
|
|
||||||
_pickable.name, _holder_desc(), net_held_by
|
|
||||||
]
|
|
||||||
)
|
|
||||||
_pickable.drop()
|
|
||||||
# Bail out when we're already in the follow-the-sync state. Without this the
|
|
||||||
# writes below (and the line logged with them) repeated every tick for every
|
|
||||||
# item on every non-authority peer — 90% of the log, plus four redundant
|
|
||||||
# physics-property writes per item per tick. The comparison also means we
|
|
||||||
# still re-apply if something else perturbs the state (e.g. let_go()
|
|
||||||
# restoring the collision mask after a force-drop).
|
|
||||||
var want_enabled := (net_held_by == 0)
|
|
||||||
if _pickable.freeze \
|
|
||||||
and _pickable.freeze_mode == RigidBody3D.FREEZE_MODE_KINEMATIC \
|
|
||||||
and _pickable.collision_mask == 0 \
|
|
||||||
and _pickable.enabled == want_enabled:
|
|
||||||
return
|
|
||||||
if NetworkManager.is_online():
|
|
||||||
print("%s: freezing (non-authority, owner=peer %d)" % [_pickable.name, net_held_by])
|
|
||||||
_pickable.freeze = true
|
|
||||||
_pickable.freeze_mode = RigidBody3D.FREEZE_MODE_KINEMATIC
|
|
||||||
_pickable.collision_mask = 0
|
|
||||||
_pickable.enabled = want_enabled
|
|
||||||
|
|
||||||
|
|
||||||
## Local hand grab (not a station snap zone, which is server-only): request
|
|
||||||
## authority immediately so the throw/drop can be reconciled, but let the grab
|
|
||||||
## happen instantly here rather than waiting on the round trip.
|
|
||||||
func _on_picked_up(_p) -> void:
|
|
||||||
var by := _pickable.get_picked_up_by()
|
|
||||||
if not (by is XRToolsFunctionPickup):
|
|
||||||
# e.g. a station snap zone grabbed it (server-side auto-snap, or the
|
|
||||||
# addon's own "grab out of a snap zone" shortcut mid-cascade) — not a
|
|
||||||
# player-initiated hand grab, so no authority request from here.
|
|
||||||
if NetworkManager.is_online():
|
|
||||||
print("%s picked up by %s (not a hand) — no authority request" % [_pickable.name, _holder_desc()])
|
|
||||||
return
|
|
||||||
if NetworkManager.is_online():
|
|
||||||
print("%s grabbed by hand (authority was peer %d), requesting authority" % [_pickable.name, net_held_by])
|
|
||||||
NetworkManager.request_item_authority_from(_pickable.get_path())
|
|
||||||
|
|
||||||
|
|
||||||
func _on_dropped(_p) -> void:
|
|
||||||
# Only forward if we're actually still the authority — a drop caused by
|
|
||||||
# apply_held_state() losing authority (see above) must not re-report.
|
|
||||||
if not is_multiplayer_authority():
|
|
||||||
if NetworkManager.is_online():
|
|
||||||
print("%s dropped locally, but we aren't its authority (peer %d is) — not reporting" % [_pickable.name, net_held_by])
|
|
||||||
return
|
|
||||||
if NetworkManager.is_online():
|
|
||||||
print("%s dropped, reporting release to server (lin=%s ang=%s)" % [
|
|
||||||
_pickable.name, _pickable.linear_velocity, _pickable.angular_velocity
|
|
||||||
])
|
|
||||||
# Send our own final transform too: we were the authority until now, and the
|
|
||||||
# server's copy may not have received our last position sync yet.
|
|
||||||
NetworkManager.release_item_authority_from(
|
|
||||||
_pickable.get_path(), _pickable.linear_velocity, _pickable.angular_velocity,
|
|
||||||
_pickable.global_transform
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
## Human-readable description of what's currently holding this item on THIS
|
|
||||||
## peer, for diagnosing desyncs between a hand's own "what am I holding"
|
|
||||||
## bookkeeping and the item's actual grab state (see the snap-zone-grab race
|
|
||||||
## in NetworkManager._try_snap_into_station for a real example).
|
|
||||||
func _holder_desc() -> String:
|
|
||||||
if not _pickable or not _pickable.is_picked_up():
|
|
||||||
return "loose"
|
|
||||||
var by := _pickable.get_picked_up_by()
|
|
||||||
if not by:
|
|
||||||
return "held(no grabber?)"
|
|
||||||
if by is XRToolsFunctionPickup:
|
|
||||||
return "hand(%s)" % by.get_path()
|
|
||||||
if by is XRToolsSnapZone:
|
|
||||||
var station := by.get_parent()
|
|
||||||
return "zone(%s)" % (station.name if station else str(by.get_path()))
|
|
||||||
return "other(%s: %s)" % [by.get_class(), by.get_path()]
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
uid://bwd0pe2udb5xo
|
|
||||||
+26
-255
@@ -24,15 +24,9 @@ signal connection_failed()
|
|||||||
var _world: Node = null
|
var _world: Node = null
|
||||||
var _players_spawner: MultiplayerSpawner = null
|
var _players_spawner: MultiplayerSpawner = null
|
||||||
var _items_spawner: MultiplayerSpawner = null
|
var _items_spawner: MultiplayerSpawner = null
|
||||||
var _content_root: Node = null
|
|
||||||
|
|
||||||
var _log_file: FileAccess
|
var _log_file: FileAccess
|
||||||
|
|
||||||
## Reason the session ended, shown by the menu on the next _ready() (see
|
|
||||||
## take_status). Avoids depending on a live signal connection to a panel that
|
|
||||||
## doesn't exist yet at the moment the session actually ends.
|
|
||||||
var last_status := ""
|
|
||||||
|
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
_open_log()
|
_open_log()
|
||||||
@@ -86,69 +80,26 @@ func _go_offline() -> void:
|
|||||||
if multiplayer.multiplayer_peer:
|
if multiplayer.multiplayer_peer:
|
||||||
multiplayer.multiplayer_peer.close()
|
multiplayer.multiplayer_peer.close()
|
||||||
multiplayer.multiplayer_peer = OfflineMultiplayerPeer.new()
|
multiplayer.multiplayer_peer = OfflineMultiplayerPeer.new()
|
||||||
unregister_world()
|
|
||||||
|
|
||||||
|
|
||||||
# --- Item spawning ---------------------------------------------------------
|
# --- Item spawning ---------------------------------------------------------
|
||||||
|
|
||||||
## Spawn a networked item. Server-only when online (replicates to all peers via
|
## Spawn a networked item. Server-only when online (replicates to all peers via
|
||||||
## the ItemsSpawner, including late joiners); works directly when offline.
|
## the ItemsSpawner); works directly when offline. Returns the new node on the
|
||||||
## node_name gives the spawned node a deterministic, identical name on every
|
## machine that owns spawning, else null.
|
||||||
## peer (needed for NodePath-based RPCs to resolve it); props are applied to
|
func spawn_item(scene_path: String, xform: Transform3D) -> Node:
|
||||||
## the instance before it enters the tree, so exported vars land correctly.
|
|
||||||
## Returns the new node on the machine that owns spawning, else null.
|
|
||||||
func spawn_item(scene_path: String, xform: Transform3D, node_name: String = "", props: Dictionary = {}) -> Node:
|
|
||||||
if is_online() and not is_server():
|
if is_online() and not is_server():
|
||||||
return null
|
return null
|
||||||
var data := {"scene": scene_path, "xform": xform, "name": node_name, "props": props}
|
var data := {"scene": scene_path, "xform": xform}
|
||||||
var via := "spawner" if (is_online() and _items_spawner) else "offline"
|
|
||||||
log_line("spawn_item: %s (name=%s, via=%s)" % [scene_path.get_file(), node_name, via])
|
|
||||||
if is_online() and _items_spawner:
|
if is_online() and _items_spawner:
|
||||||
return _items_spawner.spawn(data)
|
return _items_spawner.spawn(data)
|
||||||
# Offline: instantiate directly under the registered content root, or (for
|
# Offline: instantiate directly under the world.
|
||||||
# scenes that never call register_world, e.g. the offline menu/dev scenes)
|
|
||||||
# the current scene, so this keeps working without every offline scene
|
|
||||||
# needing to opt in.
|
|
||||||
var inst := _spawn_item_from_data(data)
|
var inst := _spawn_item_from_data(data)
|
||||||
if inst:
|
if _world and inst:
|
||||||
var parent: Node = _content_root if _content_root else get_tree().current_scene
|
_world.add_child(inst)
|
||||||
if parent:
|
|
||||||
parent.add_child(inst)
|
|
||||||
return inst
|
return inst
|
||||||
|
|
||||||
|
|
||||||
## Despawn a server-spawned item. MultiplayerSpawner broadcasts a despawn to
|
|
||||||
## every peer when a tracked node exits the tree on the authority, so this is
|
|
||||||
## the single seam for destroying spawned items (works offline too).
|
|
||||||
func despawn_item(node: Node) -> void:
|
|
||||||
if not owns_world() or not is_instance_valid(node):
|
|
||||||
return
|
|
||||||
log_line("despawn_item: %s" % node.name)
|
|
||||||
# Items that came from the ItemsSpawner are despawned on every peer
|
|
||||||
# automatically when they leave the tree here. Items baked into a scene file
|
|
||||||
# are unknown to the spawner, so their removal has to be broadcast
|
|
||||||
# explicitly — otherwise every client keeps a ghost copy of an item the
|
|
||||||
# server has consumed, which then blocks the station it was sitting in and
|
|
||||||
# gets grabbed instead of the real item that replaced it.
|
|
||||||
if is_online() and not _is_spawner_tracked(node):
|
|
||||||
_despawn_static_item.rpc(node.get_path())
|
|
||||||
node.queue_free()
|
|
||||||
|
|
||||||
|
|
||||||
# Items the ItemsSpawner replicates live under its spawn path; anything else was
|
|
||||||
# baked into the scene file and the spawner knows nothing about it.
|
|
||||||
func _is_spawner_tracked(node: Node) -> bool:
|
|
||||||
return _content_root != null and _content_root.is_ancestor_of(node)
|
|
||||||
|
|
||||||
|
|
||||||
@rpc("authority", "call_remote", "reliable")
|
|
||||||
func _despawn_static_item(path: NodePath) -> void:
|
|
||||||
var node := get_node_or_null(path)
|
|
||||||
if node:
|
|
||||||
log_line("despawn_static_item: freeing %s (the server consumed it)" % node.name)
|
|
||||||
node.queue_free()
|
|
||||||
|
|
||||||
|
|
||||||
# MultiplayerSpawner custom spawn function: runs on every peer to build the node
|
# MultiplayerSpawner custom spawn function: runs on every peer to build the node
|
||||||
# from the replicated payload.
|
# from the replicated payload.
|
||||||
func _spawn_item_from_data(data: Variant) -> Node:
|
func _spawn_item_from_data(data: Variant) -> Node:
|
||||||
@@ -159,135 +110,50 @@ func _spawn_item_from_data(data: Variant) -> Node:
|
|||||||
var inst := scene.instantiate()
|
var inst := scene.instantiate()
|
||||||
if inst is Node3D:
|
if inst is Node3D:
|
||||||
inst.transform = data["xform"]
|
inst.transform = data["xform"]
|
||||||
if data.get("name", "") != "":
|
|
||||||
inst.name = data["name"]
|
|
||||||
for key in data.get("props", {}):
|
|
||||||
inst.set(key, data["props"][key])
|
|
||||||
if not owns_world():
|
|
||||||
_gate_station(inst)
|
|
||||||
return inst
|
return inst
|
||||||
|
|
||||||
|
|
||||||
# Stations run their own logic and auto-grab (XRToolsSnapZone with
|
|
||||||
# snap_mode=RANGE) identically on every peer by default, which would let each
|
|
||||||
# peer independently grab/simulate the same shared object. Disable both on
|
|
||||||
# every peer except the one that owns world logic; the server-authoritative
|
|
||||||
# item-authority RPCs are what let clients still grab a server-held item by
|
|
||||||
# hand. Runs before the node enters the tree, so its own _ready() sees the
|
|
||||||
# final (disabled) state.
|
|
||||||
func _gate_station(node: Node) -> void:
|
|
||||||
if not (node is StaticBody3D):
|
|
||||||
return
|
|
||||||
for child in node.get_children():
|
|
||||||
if child is XRToolsSnapZone:
|
|
||||||
child.enabled = false
|
|
||||||
child.set_process(false)
|
|
||||||
node.set_process(false)
|
|
||||||
log_line("gated station (non-owner peer): %s" % node.name)
|
|
||||||
|
|
||||||
|
|
||||||
## Gate every station already sitting in the scene tree, for peers that don't
|
|
||||||
## own world logic. Stations that arrive through spawn_item() are gated as they
|
|
||||||
## are built (see _spawn_item_from_data), but ones baked into a scene file never
|
|
||||||
## pass through there — leaving a client running its own snap zones, which then
|
|
||||||
## grab items straight out of the local hand and fight the server's
|
|
||||||
## authoritative placement. Idempotent, so it's safe on every session start.
|
|
||||||
func gate_existing_stations() -> void:
|
|
||||||
if owns_world():
|
|
||||||
return
|
|
||||||
for station in get_tree().get_nodes_in_group("station"):
|
|
||||||
_gate_station(station)
|
|
||||||
|
|
||||||
|
|
||||||
# --- Item grab-authority transfer -----------------------------------------
|
# --- Item grab-authority transfer -----------------------------------------
|
||||||
|
|
||||||
## Called by NetPickable when this peer grabs an item by hand. Godot rejects
|
## A client (or host) requests authority over an item it just grabbed. Runs on
|
||||||
## rpc_id() targeting your own peer id ("RPC on yourself is not allowed"), so
|
## the server. If the item was snapped into a station, the station releases it
|
||||||
## when we ARE the server this runs the logic directly instead of round-
|
## so the grabber cleanly takes ownership.
|
||||||
## tripping an RPC to ourselves — otherwise every host-side grab/drop was
|
|
||||||
## silently failing to run its server-side half (no denial checks, and
|
|
||||||
## crucially no auto-snap-into-station on release).
|
|
||||||
func request_item_authority_from(item_path: NodePath) -> void:
|
|
||||||
if is_server():
|
|
||||||
_grant_or_reject_item_authority(item_path, multiplayer.get_unique_id())
|
|
||||||
else:
|
|
||||||
_request_item_authority_rpc.rpc_id(1, item_path)
|
|
||||||
|
|
||||||
|
|
||||||
@rpc("any_peer", "reliable")
|
@rpc("any_peer", "reliable")
|
||||||
func _request_item_authority_rpc(item_path: NodePath) -> void:
|
func request_item_authority(item_path: NodePath) -> void:
|
||||||
if not is_server():
|
if not is_server():
|
||||||
return
|
return
|
||||||
_grant_or_reject_item_authority(item_path, multiplayer.get_remote_sender_id())
|
var sender := multiplayer.get_remote_sender_id()
|
||||||
|
|
||||||
|
|
||||||
## Runs on the server (called directly if the requester IS the server, or via
|
|
||||||
## the RPC above otherwise). If the item was snapped into a station, the
|
|
||||||
## station releases it so the grabber cleanly takes ownership.
|
|
||||||
func _grant_or_reject_item_authority(item_path: NodePath, sender: int) -> void:
|
|
||||||
var item := get_node_or_null(item_path)
|
|
||||||
if item:
|
|
||||||
var np := item.get_node_or_null("NetPickable")
|
|
||||||
if np and np.net_held_by != 0 and np.net_held_by != sender:
|
|
||||||
# Already legitimately held by a different live peer: reject the
|
|
||||||
# requester's optimistic client-side grab instead of stealing it.
|
|
||||||
log_line("request_item_authority: DENIED %s to peer %d (already held by %d)" % [item.name, sender, np.net_held_by])
|
|
||||||
_force_release_item_to(sender, item_path)
|
|
||||||
return
|
|
||||||
log_line("request_item_authority: granting %s to peer %d" % [str(item.name) if item else str(item_path), sender])
|
|
||||||
# Assign authority + held state first (disables the item on the server so its
|
# Assign authority + held state first (disables the item on the server so its
|
||||||
# snap zone won't re-grab it), then release it from any station.
|
# snap zone won't re-grab it), then release it from any station.
|
||||||
_set_item_authority.rpc(item_path, sender)
|
_set_item_authority.rpc(item_path, sender)
|
||||||
|
var item := get_node_or_null(item_path)
|
||||||
if item:
|
if item:
|
||||||
_release_from_snap_zones(item)
|
_release_from_snap_zones(item)
|
||||||
|
|
||||||
|
|
||||||
## Called by NetPickable when this peer releases an item, forwarding its throw
|
## A player releases an item, forwarding its throw velocity so the server can
|
||||||
## velocity so the server can resume simulating it. Same self-RPC issue as
|
## resume simulating it. Runs on the server. If released next to a station, the
|
||||||
## above: runs directly if we're the server.
|
## server snaps it in (server-authoritative placement).
|
||||||
func release_item_authority_from(item_path: NodePath, lin: Vector3, ang: Vector3, xform: Transform3D) -> void:
|
|
||||||
if is_server():
|
|
||||||
_do_release_item_authority(item_path, lin, ang, xform, multiplayer.get_unique_id())
|
|
||||||
else:
|
|
||||||
_release_item_authority_rpc.rpc_id(1, item_path, lin, ang, xform)
|
|
||||||
|
|
||||||
|
|
||||||
@rpc("any_peer", "reliable")
|
@rpc("any_peer", "reliable")
|
||||||
func _release_item_authority_rpc(item_path: NodePath, lin: Vector3, ang: Vector3, xform: Transform3D) -> void:
|
func release_item_authority(item_path: NodePath, lin: Vector3, ang: Vector3) -> void:
|
||||||
if not is_server():
|
if not is_server():
|
||||||
return
|
return
|
||||||
_do_release_item_authority(item_path, lin, ang, xform, multiplayer.get_remote_sender_id())
|
|
||||||
|
|
||||||
|
|
||||||
## Runs on the server. If released next to a station, the server snaps it in
|
|
||||||
## (server-authoritative placement).
|
|
||||||
func _do_release_item_authority(item_path: NodePath, lin: Vector3, ang: Vector3, xform: Transform3D, sender: int) -> void:
|
|
||||||
log_line("release_item_authority: %s released by peer %d" % [str(item_path), sender])
|
|
||||||
_set_item_authority.rpc(item_path, 1)
|
_set_item_authority.rpc(item_path, 1)
|
||||||
var item := get_node_or_null(item_path)
|
var item := get_node_or_null(item_path)
|
||||||
if item is RigidBody3D:
|
if item is RigidBody3D:
|
||||||
# Adopt the releasing peer's own final transform rather than trusting our
|
|
||||||
# copy's. That peer was the item's authority right up to this moment, and
|
|
||||||
# its position updates travel on the synchronizer's separate, unordered
|
|
||||||
# channel — this reliable RPC routinely overtakes them, leaving our copy
|
|
||||||
# still sitting where the item was BEFORE the peer carried it away. The
|
|
||||||
# snap decision below then reads that stale position and teleports the
|
|
||||||
# item straight back into the station it was just picked up from.
|
|
||||||
item.global_transform = xform
|
|
||||||
item.freeze = false
|
item.freeze = false
|
||||||
item.linear_velocity = lin
|
item.linear_velocity = lin
|
||||||
item.angular_velocity = ang
|
item.angular_velocity = ang
|
||||||
_try_snap_into_station.call_deferred(item)
|
_try_snap_into_station(item)
|
||||||
|
|
||||||
|
|
||||||
# All station snap zones in the world (every XRToolsSnapZone child of a node in
|
# All station snap zones in the world (nodes in the "station" group).
|
||||||
# the "station" group — some stations, e.g. Table, have more than one).
|
|
||||||
func _station_snap_zones() -> Array:
|
func _station_snap_zones() -> Array:
|
||||||
var zones := []
|
var zones := []
|
||||||
for station in get_tree().get_nodes_in_group("station"):
|
for station in get_tree().get_nodes_in_group("station"):
|
||||||
for child in station.get_children():
|
var zone = station.get_node_or_null("XRToolsSnapZone")
|
||||||
if child is XRToolsSnapZone:
|
if zone:
|
||||||
zones.append(child)
|
zones.append(zone)
|
||||||
return zones
|
return zones
|
||||||
|
|
||||||
|
|
||||||
@@ -295,41 +161,19 @@ func _station_snap_zones() -> Array:
|
|||||||
func _release_from_snap_zones(item: Node) -> void:
|
func _release_from_snap_zones(item: Node) -> void:
|
||||||
for zone in _station_snap_zones():
|
for zone in _station_snap_zones():
|
||||||
if zone.picked_up_object == item:
|
if zone.picked_up_object == item:
|
||||||
log_line("releasing %s from %s's snap zone (authority just granted elsewhere)" % [item.name, zone.get_parent().name])
|
|
||||||
zone.drop_object()
|
zone.drop_object()
|
||||||
|
|
||||||
|
|
||||||
# Snap the item into the nearest empty station snap zone within grab range.
|
# Snap the item into the nearest empty station snap zone within grab range.
|
||||||
#
|
|
||||||
# Called deferred from _do_release_item_authority: XRToolsFunctionPickup's own
|
|
||||||
# "grab an item out of a snap zone" path calls zone.drop_object() BEFORE it
|
|
||||||
# calls pick_up() on the hand's behalf. drop_object()'s let_go() synchronously
|
|
||||||
# fires the pickable's `dropped` signal, which (via NetPickable) lands here —
|
|
||||||
# if this ran synchronously it would immediately re-snap the item into the
|
|
||||||
# very same zone it's still physically inside, stealing it away before the
|
|
||||||
# hand's own pick_up() call (later in the same call stack) ever runs. That
|
|
||||||
# leaves XRToolsFunctionPickup.picked_up_object pointing at an item whose
|
|
||||||
# _grab_driver actually belongs to the zone — a stale reference that crashes
|
|
||||||
# (null _grab_driver) the next time a controller button is pressed. Deferring
|
|
||||||
# lets the hand's pick_up() go first; the is_picked_up() check below is a
|
|
||||||
# second guard in case the item gets grabbed for real before this runs.
|
|
||||||
func _try_snap_into_station(item: Node) -> void:
|
func _try_snap_into_station(item: Node) -> void:
|
||||||
if not (item is Node3D):
|
if not (item is Node3D):
|
||||||
return
|
return
|
||||||
if item.has_method("is_picked_up") and item.is_picked_up():
|
|
||||||
var by: Node = null
|
|
||||||
if item.has_method("get_picked_up_by"):
|
|
||||||
by = item.get_picked_up_by()
|
|
||||||
log_line("skipped snapping %s: already held by %s (grab-race guard)" % [item.name, by.get_path() if by else "?"])
|
|
||||||
return
|
|
||||||
for zone in _station_snap_zones():
|
for zone in _station_snap_zones():
|
||||||
if is_instance_valid(zone.picked_up_object):
|
if is_instance_valid(zone.picked_up_object):
|
||||||
continue
|
continue
|
||||||
if zone.global_position.distance_to(item.global_position) <= zone.grab_distance:
|
if zone.global_position.distance_to(item.global_position) <= zone.grab_distance:
|
||||||
log_line("snapped %s into %s" % [item.name, zone.get_parent().name])
|
|
||||||
zone.pick_up_object(item)
|
zone.pick_up_object(item)
|
||||||
return
|
return
|
||||||
log_line("no station in range to snap %s into (or none empty)" % item.name)
|
|
||||||
|
|
||||||
|
|
||||||
# Server broadcasts an authority assignment so every peer agrees on who owns the
|
# Server broadcasts an authority assignment so every peer agrees on who owns the
|
||||||
@@ -339,7 +183,6 @@ func _set_item_authority(item_path: NodePath, peer: int) -> void:
|
|||||||
var item := get_node_or_null(item_path)
|
var item := get_node_or_null(item_path)
|
||||||
if not item:
|
if not item:
|
||||||
return
|
return
|
||||||
log_line("_set_item_authority: %s -> peer %d" % [item.name, peer])
|
|
||||||
item.set_multiplayer_authority(peer) # recursive: item + synchronizer + NetPickable
|
item.set_multiplayer_authority(peer) # recursive: item + synchronizer + NetPickable
|
||||||
var np := item.get_node_or_null("NetPickable")
|
var np := item.get_node_or_null("NetPickable")
|
||||||
if np:
|
if np:
|
||||||
@@ -347,28 +190,6 @@ func _set_item_authority(item_path: NodePath, peer: int) -> void:
|
|||||||
np.apply_held_state()
|
np.apply_held_state()
|
||||||
|
|
||||||
|
|
||||||
## Rejects peer's optimistic grab (the item was already legitimately held by
|
|
||||||
## someone else). Same self-RPC concern: if the rejected peer is the server
|
|
||||||
## itself, apply it directly rather than rpc_id-ing ourselves.
|
|
||||||
func _force_release_item_to(peer: int, item_path: NodePath) -> void:
|
|
||||||
if peer == 1:
|
|
||||||
_do_force_release(item_path)
|
|
||||||
else:
|
|
||||||
force_release_item.rpc_id(peer, item_path)
|
|
||||||
|
|
||||||
|
|
||||||
@rpc("authority", "reliable")
|
|
||||||
func force_release_item(item_path: NodePath) -> void:
|
|
||||||
_do_force_release(item_path)
|
|
||||||
|
|
||||||
|
|
||||||
func _do_force_release(item_path: NodePath) -> void:
|
|
||||||
log_line("force_release_item: dropping %s (server rejected our grab)" % str(item_path))
|
|
||||||
var item := get_node_or_null(item_path)
|
|
||||||
if item and item.has_method("drop"):
|
|
||||||
item.drop()
|
|
||||||
|
|
||||||
|
|
||||||
func is_server() -> bool:
|
func is_server() -> bool:
|
||||||
return is_online() and multiplayer.is_server()
|
return is_online() and multiplayer.is_server()
|
||||||
|
|
||||||
@@ -399,72 +220,24 @@ func submit_work(station_path: NodePath, amount: float) -> void:
|
|||||||
return
|
return
|
||||||
var station := get_node_or_null(station_path)
|
var station := get_node_or_null(station_path)
|
||||||
if station and station.has_method("add_work"):
|
if station and station.has_method("add_work"):
|
||||||
log_line("submit_work: peer %d contributed %.2f to %s" % [multiplayer.get_remote_sender_id(), amount, station.name])
|
|
||||||
station.add_work(multiplayer.get_remote_sender_id(), amount)
|
station.add_work(multiplayer.get_remote_sender_id(), amount)
|
||||||
|
|
||||||
|
|
||||||
## Called by the world scene once it's ready, passing its spawners. Must run
|
## Called by main.gd once the world scene is ready, passing its spawners.
|
||||||
## before world_ready()/host()/join() on every peer so the custom spawn
|
|
||||||
## function is installed before any spawn packet can arrive.
|
|
||||||
func register_world(world: Node, players_spawner: MultiplayerSpawner, items_spawner: MultiplayerSpawner) -> void:
|
func register_world(world: Node, players_spawner: MultiplayerSpawner, items_spawner: MultiplayerSpawner) -> void:
|
||||||
_world = world
|
_world = world
|
||||||
_players_spawner = players_spawner
|
_players_spawner = players_spawner
|
||||||
_items_spawner = items_spawner
|
_items_spawner = items_spawner
|
||||||
_content_root = items_spawner.get_node(items_spawner.spawn_path) if items_spawner else world
|
|
||||||
if _items_spawner:
|
if _items_spawner:
|
||||||
_items_spawner.spawn_function = _spawn_item_from_data
|
_items_spawner.spawn_function = _spawn_item_from_data
|
||||||
log_line("World registered (players_spawner=%s items_spawner=%s)" % [str(players_spawner != null), str(items_spawner != null)])
|
log_line("World registered (players_spawner=%s items_spawner=%s)" % [str(players_spawner != null), str(items_spawner != null)])
|
||||||
|
|
||||||
|
|
||||||
## Called when the world scene goes away (disconnect, leaving the session) so
|
|
||||||
## the autoload doesn't hold stale/freed references across a scene reload.
|
|
||||||
func unregister_world() -> void:
|
|
||||||
_world = null
|
|
||||||
_content_root = null
|
|
||||||
_players_spawner = null
|
|
||||||
_items_spawner = null
|
|
||||||
|
|
||||||
|
|
||||||
## Returns the reason the last session ended (if any) and clears it. The menu
|
|
||||||
## pulls this on its own _ready() rather than depending on a live signal
|
|
||||||
## connection to a panel that doesn't exist yet when the session ends.
|
|
||||||
func take_status() -> String:
|
|
||||||
var s := last_status
|
|
||||||
last_status = ""
|
|
||||||
return s
|
|
||||||
|
|
||||||
|
|
||||||
## Called by main.gd after it has registered the world and connected its
|
## Called by main.gd after it has registered the world and connected its
|
||||||
## player_joined/left listeners. Kicks off any menu- or command-line-driven
|
## player_joined/left listeners. Kicks off any command-line driven session so
|
||||||
## session so that session signals never fire before the world is listening.
|
## that session signals never fire before the world is listening.
|
||||||
func world_ready() -> void:
|
func world_ready() -> void:
|
||||||
consume_pending_session()
|
_handle_cmdline()
|
||||||
|
|
||||||
|
|
||||||
# --- Menu-driven session request -------------------------------------------
|
|
||||||
|
|
||||||
# Set by the main menu's Host/Join buttons before switching to the multiplayer
|
|
||||||
# scene; consumed once that scene's world is ready to listen for session
|
|
||||||
# signals (avoids a race between change_scene_to_file and connection callbacks).
|
|
||||||
var pending_action := ""
|
|
||||||
var pending_ip := ""
|
|
||||||
|
|
||||||
func request_host() -> void:
|
|
||||||
pending_action = "host"
|
|
||||||
|
|
||||||
func request_join(ip: String) -> void:
|
|
||||||
pending_action = "join"
|
|
||||||
pending_ip = ip
|
|
||||||
|
|
||||||
func consume_pending_session() -> void:
|
|
||||||
if pending_action == "host":
|
|
||||||
pending_action = ""
|
|
||||||
host()
|
|
||||||
elif pending_action == "join":
|
|
||||||
pending_action = ""
|
|
||||||
join(pending_ip)
|
|
||||||
else:
|
|
||||||
_handle_cmdline()
|
|
||||||
|
|
||||||
|
|
||||||
# --- Session signal handlers ----------------------------------------------
|
# --- Session signal handlers ----------------------------------------------
|
||||||
@@ -487,13 +260,11 @@ func _on_connected_to_server() -> void:
|
|||||||
func _on_connection_failed() -> void:
|
func _on_connection_failed() -> void:
|
||||||
log_line("connection_failed")
|
log_line("connection_failed")
|
||||||
_go_offline()
|
_go_offline()
|
||||||
last_status = "Could not connect"
|
|
||||||
connection_failed.emit()
|
connection_failed.emit()
|
||||||
|
|
||||||
func _on_server_disconnected() -> void:
|
func _on_server_disconnected() -> void:
|
||||||
log_line("server_disconnected")
|
log_line("server_disconnected")
|
||||||
_go_offline()
|
_go_offline()
|
||||||
last_status = "Host disconnected"
|
|
||||||
session_ended.emit()
|
session_ended.emit()
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
extends Node3D
|
||||||
|
|
||||||
|
## World-space main menu: hosts the 2D join_panel on an XRToolsViewport2DIn3D so
|
||||||
|
## the player can point at it with a controller laser. Re-emits the panel's
|
||||||
|
## intents; main.gd drives the actual networking.
|
||||||
|
|
||||||
|
signal host_pressed()
|
||||||
|
signal join_pressed(ip: String)
|
||||||
|
signal solo_pressed()
|
||||||
|
|
||||||
|
@onready var _vp: XRToolsViewport2DIn3D = $Viewport2Din3D
|
||||||
|
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
# The viewport instantiates its 2D scene during its own _ready; connect once
|
||||||
|
# that has happened.
|
||||||
|
_connect_scene.call_deferred()
|
||||||
|
|
||||||
|
|
||||||
|
func _connect_scene() -> void:
|
||||||
|
_vp.connect_scene_signal("host_pressed", func(): host_pressed.emit())
|
||||||
|
_vp.connect_scene_signal("join_pressed", func(ip): join_pressed.emit(ip))
|
||||||
|
_vp.connect_scene_signal("solo_pressed", func(): solo_pressed.emit())
|
||||||
|
|
||||||
|
|
||||||
|
func show_menu() -> void:
|
||||||
|
visible = true
|
||||||
|
|
||||||
|
|
||||||
|
func hide_menu() -> void:
|
||||||
|
visible = false
|
||||||
|
|
||||||
|
|
||||||
|
func set_status(text: String) -> void:
|
||||||
|
var scene := _vp.get_scene_instance()
|
||||||
|
if scene and scene.has_method("set_status"):
|
||||||
|
scene.set_status(text)
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://1o2nca75po1f
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
[gd_scene load_steps=4 format=3]
|
||||||
|
|
||||||
|
[ext_resource type="Script" path="res://Net/network_menu.gd" id="1_menu"]
|
||||||
|
[ext_resource type="PackedScene" uid="uid://clujaf3u776a3" path="res://addons/godot-xr-tools/objects/viewport_2d_in_3d.tscn" id="2_vp"]
|
||||||
|
[ext_resource type="PackedScene" path="res://Net/join_panel.tscn" id="3_panel"]
|
||||||
|
|
||||||
|
[node name="NetworkMenu" type="Node3D"]
|
||||||
|
script = ExtResource("1_menu")
|
||||||
|
|
||||||
|
[node name="Viewport2Din3D" parent="." instance=ExtResource("2_vp")]
|
||||||
|
screen_size = Vector2(0.6, 0.4)
|
||||||
|
scene = ExtResource("3_panel")
|
||||||
|
viewport_size = Vector2(600, 400)
|
||||||
@@ -1,81 +0,0 @@
|
|||||||
class_name WorldLayout
|
|
||||||
|
|
||||||
## Data-driven description of what's in the multiplayer world. The server (or
|
|
||||||
## the single machine, when offline) spawns every entry through
|
|
||||||
## NetworkManager.spawn_item() instead of baking these into the scene file, so
|
|
||||||
## a joining client receives them from the server rather than assuming its own
|
|
||||||
## copy of the scene matches. Swapping the contents of these two functions is
|
|
||||||
## the only change needed for a future varying/procedural layout.
|
|
||||||
##
|
|
||||||
## Positions below are transcribed verbatim from the previous baked layout in
|
|
||||||
## Scenes/multiPlayer.tscn so the starting world is unchanged.
|
|
||||||
|
|
||||||
static func get_stations() -> Array[Dictionary]:
|
|
||||||
return [
|
|
||||||
{"scene": "res://Stations/Hob.tscn", "name": "Hob",
|
|
||||||
"xform": Transform3D(Basis(), Vector3(0.29336345, 0.8981018, -1.484)), "props": {}},
|
|
||||||
{"scene": "res://Stations/BurgerBunsDispenser.tscn", "name": "BurgerBunsDispenser",
|
|
||||||
"xform": Transform3D(Basis(), Vector3(-1.832131, 0.40028095, -1.4813508)), "props": {}},
|
|
||||||
{"scene": "res://Stations/sink.tscn", "name": "Sink",
|
|
||||||
"xform": Transform3D(Basis(), Vector3(1.3140475, 0.9061539, -1.4941733)), "props": {}},
|
|
||||||
{"scene": "res://Stations/dirt_station.tscn", "name": "DirtStation",
|
|
||||||
"xform": Transform3D(Basis(), Vector3(2.0864775, 0.8981018, -1.244947)), "props": {}},
|
|
||||||
{"scene": "res://Stations/Counter.tscn", "name": "Counter",
|
|
||||||
"xform": Transform3D(Basis(), Vector3(-0.7124918, 0.90304357, -1.4886917)), "props": {}},
|
|
||||||
{"scene": "res://Stations/Counter.tscn", "name": "Counter2",
|
|
||||||
"xform": Transform3D(Vector3(-4.371139e-08, 0.0, 1.0), Vector3(0.0, 1.0, 0.0), Vector3(-1.0, 0.0, -4.371139e-08), Vector3(-1.7648025, 0.90304357, -0.4458799)), "props": {}},
|
|
||||||
{"scene": "res://Stations/Counter.tscn", "name": "Counter3",
|
|
||||||
"xform": Transform3D(Vector3(-4.371139e-08, 0.0, 1.0), Vector3(0.0, 1.0, 0.0), Vector3(-1.0, 0.0, -4.371139e-08), Vector3(-1.7648025, 0.90304357, 0.55367994)), "props": {}},
|
|
||||||
{"scene": "res://Stations/Counter.tscn", "name": "Counter4",
|
|
||||||
"xform": Transform3D(Vector3(-4.371139e-08, 0.0, 1.0), Vector3(0.0, 1.0, 0.0), Vector3(-1.0, 0.0, -4.371139e-08), Vector3(-1.7648025, 0.90304357, 1.5539298)), "props": {}},
|
|
||||||
{"scene": "res://Stations/table.tscn", "name": "Table",
|
|
||||||
"xform": Transform3D(Basis(), Vector3(1.633146, 0.9030438, 1.1343781)),
|
|
||||||
"props": {
|
|
||||||
"initial_thinking_time": 8.0,
|
|
||||||
"initial_primary_time": 40.0,
|
|
||||||
"initial_friend_time": 3.0,
|
|
||||||
"initial_eating_time": 3.0,
|
|
||||||
}},
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
static func get_items() -> Array[Dictionary]:
|
|
||||||
var items: Array[Dictionary] = []
|
|
||||||
|
|
||||||
items.append(_item("res://Items/BurgerBuns.tscn", "BurgerBuns", Vector3(-1.8162017, 1.6081157, -1.4714175)))
|
|
||||||
items.append(_item("res://Items/BurgerBuns.tscn", "BurgerBuns2", Vector3(-1.3596323, 1.4110342, -0.22482127)))
|
|
||||||
|
|
||||||
items.append(_item("res://Containers/plate.tscn", "Plate", Vector3(-1.5717233, 1.5454081, 1.5373346)))
|
|
||||||
items.append(_item("res://Containers/plate.tscn", "Plate2", Vector3(-1.5730225, 1.499024, 0.59790254)))
|
|
||||||
items.append(_item("res://Containers/plate.tscn", "Plate3", Vector3(-1.5818124, 1.499024, -0.4634577)))
|
|
||||||
|
|
||||||
items.append(_item("res://Items/burger.tscn", "burger", Vector3(0.6888188, 1.4195822, -1.7110313)))
|
|
||||||
items.append(_item("res://Items/burger.tscn", "burger2", Vector3(0.6931299, 1.5300478, -1.71225)))
|
|
||||||
items.append(_item("res://Items/burger.tscn", "burger3", Vector3(0.69027674, 1.4969791, -1.7210286)))
|
|
||||||
items.append(_item("res://Items/burger.tscn", "burger4", Vector3(0.69134104, 1.4543622, -1.7210286)))
|
|
||||||
|
|
||||||
items.append(_item("res://Items/hamburger.tscn", "Hamburger", Vector3(-1.9352558, 1.623975, 1.2447833)))
|
|
||||||
items.append(_item("res://Items/hamburger.tscn", "Hamburger2", Vector3(-1.9857153, 1.5329368, 0.9472374)))
|
|
||||||
items.append(_item("res://Items/hamburger.tscn", "Hamburger3", Vector3(-1.7201865, 1.5329367, 0.14773655)))
|
|
||||||
|
|
||||||
items.append(_item("res://Items/cooked_burger.tscn", "CookedBurger", Vector3(-0.30671906, 1.4131018, -1.0928738)))
|
|
||||||
items.append(_item("res://Items/cooked_burger.tscn", "CookedBurger2", Vector3(-0.30671906, 1.4496142, -1.0928738)))
|
|
||||||
items.append(_item("res://Items/cooked_burger.tscn", "CookedBurger3", Vector3(-1.3344773, 1.4398065, -0.7096845)))
|
|
||||||
items.append(_item("res://Items/cooked_burger.tscn", "CookedBurger4", Vector3(-0.30671906, 1.525444, -1.0928738)))
|
|
||||||
|
|
||||||
items.append(_item("res://Items/PickupCube.tscn", "PickableObject", Vector3(0.6225724, 1.4792972, -1.0473135)))
|
|
||||||
items.append(_item("res://Items/PickupCube.tscn", "PickableObject2", Vector3(0.6359743, 1.4639391, -1.1673055)))
|
|
||||||
items.append(_item("res://Items/PickupCube.tscn", "PickableObject3", Vector3(0.5142721, 1.4792972, -1.0473135)))
|
|
||||||
items.append(_item("res://Items/PickupCube.tscn", "PickableObject4", Vector3(0.5276739, 1.4639391, -1.1673055)))
|
|
||||||
items.append(_item("res://Items/PickupCube.tscn", "PickableObject5", Vector3(0.73287535, 1.4792972, -1.0473135)))
|
|
||||||
items.append(_item("res://Items/PickupCube.tscn", "PickableObject6", Vector3(0.7462772, 1.4639391, -1.1673055)))
|
|
||||||
items.append(_item("res://Items/PickupCube.tscn", "PickableObject7", Vector3(-1.3556751, 1.4792972, 0.28881657)))
|
|
||||||
items.append(_item("res://Items/PickupCube.tscn", "PickableObject8", Vector3(-1.3422732, 1.4639391, 0.16882455)))
|
|
||||||
items.append(_item("res://Items/PickupCube.tscn", "PickableObject9", Vector3(-1.4639754, 1.4792972, 0.28881657)))
|
|
||||||
items.append(_item("res://Items/PickupCube.tscn", "PickableObject10", Vector3(-1.4505737, 1.4639391, 0.16882455)))
|
|
||||||
|
|
||||||
return items
|
|
||||||
|
|
||||||
|
|
||||||
static func _item(scene: String, name: String, pos: Vector3) -> Dictionary:
|
|
||||||
return {"scene": scene, "name": name, "xform": Transform3D(Basis(), pos), "props": {}}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
uid://donvkica3drtx
|
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
[gd_scene load_steps=7 format=3 uid="uid://cnetplayer0001"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" path="res://Player/player.gd" id="1_player"]
|
||||||
|
|
||||||
|
[sub_resource type="SceneReplicationConfig" id="Repl_player"]
|
||||||
|
properties/0/path = NodePath(".:head_xform")
|
||||||
|
properties/0/spawn = true
|
||||||
|
properties/0/replication_mode = 1
|
||||||
|
properties/1/path = NodePath(".:left_xform")
|
||||||
|
properties/1/spawn = true
|
||||||
|
properties/1/replication_mode = 1
|
||||||
|
properties/2/path = NodePath(".:right_xform")
|
||||||
|
properties/2/spawn = true
|
||||||
|
properties/2/replication_mode = 1
|
||||||
|
properties/3/path = NodePath(".:net_heartbeat")
|
||||||
|
properties/3/spawn = true
|
||||||
|
properties/3/replication_mode = 1
|
||||||
|
|
||||||
|
[sub_resource type="StandardMaterial3D" id="Mat_head"]
|
||||||
|
albedo_color = Color(0.85, 0.7, 0.55, 1)
|
||||||
|
|
||||||
|
[sub_resource type="BoxMesh" id="Mesh_head"]
|
||||||
|
material = SubResource("Mat_head")
|
||||||
|
size = Vector3(0.18, 0.24, 0.16)
|
||||||
|
|
||||||
|
[sub_resource type="StandardMaterial3D" id="Mat_hand"]
|
||||||
|
albedo_color = Color(0.2, 0.5, 0.9, 1)
|
||||||
|
|
||||||
|
[sub_resource type="BoxMesh" id="Mesh_hand"]
|
||||||
|
material = SubResource("Mat_hand")
|
||||||
|
size = Vector3(0.09, 0.05, 0.12)
|
||||||
|
|
||||||
|
[node name="Player" type="Node3D"]
|
||||||
|
script = ExtResource("1_player")
|
||||||
|
|
||||||
|
[node name="Avatar" type="Node3D" parent="."]
|
||||||
|
|
||||||
|
[node name="Head" type="MeshInstance3D" parent="Avatar"]
|
||||||
|
mesh = SubResource("Mesh_head")
|
||||||
|
|
||||||
|
[node name="LeftHand" type="MeshInstance3D" parent="Avatar"]
|
||||||
|
mesh = SubResource("Mesh_hand")
|
||||||
|
|
||||||
|
[node name="RightHand" type="MeshInstance3D" parent="Avatar"]
|
||||||
|
mesh = SubResource("Mesh_hand")
|
||||||
|
|
||||||
|
[node name="MultiplayerSynchronizer" type="MultiplayerSynchronizer" parent="."]
|
||||||
|
replication_config = SubResource("Repl_player")
|
||||||
@@ -1,71 +0,0 @@
|
|||||||
extends Node3D
|
|
||||||
|
|
||||||
## Networked representation of one connected player. The owning peer's local
|
|
||||||
## XR rig (found via the "local_xr_origin" group) drives Head/LeftHand/
|
|
||||||
## RightHand each frame; the MultiplayerSynchronizer replicates those
|
|
||||||
## transforms so every other peer sees a matching avatar.
|
|
||||||
|
|
||||||
@onready var _head: Node3D = $Head
|
|
||||||
@onready var _left_hand: Node3D = $LeftHand
|
|
||||||
@onready var _right_hand: Node3D = $RightHand
|
|
||||||
|
|
||||||
var _local_camera: Node3D
|
|
||||||
var _local_left_hand: Node3D
|
|
||||||
var _local_right_hand: Node3D
|
|
||||||
|
|
||||||
|
|
||||||
func _enter_tree() -> void:
|
|
||||||
# MultiplayerSynchronizer resolves authority when this node enters the
|
|
||||||
# tree, so authority must be set here rather than in _ready(), or the
|
|
||||||
# first synced frames go the wrong direction.
|
|
||||||
set_multiplayer_authority(str(name).to_int())
|
|
||||||
|
|
||||||
|
|
||||||
func _ready() -> void:
|
|
||||||
# LeftHand/RightHand are the full godot-xr-tools glove scenes, whose root
|
|
||||||
# node carries hand.gd (XRToolsHand). That script sets top_level = true
|
|
||||||
# and every physics frame does global_transform = get_parent().
|
|
||||||
# global_transform * offset — i.e. it actively repositions itself to
|
|
||||||
# track a live XRController3D parent. Here the parent is just this
|
|
||||||
# NetPlayer node, not a controller, so left running it fights (and mostly
|
|
||||||
# wins, since it runs every physics tick regardless of our own _process)
|
|
||||||
# against both the local authority's transform copy below and the
|
|
||||||
# replicated values on other peers — the exact "hands stuck near origin,
|
|
||||||
# only occasionally correct" symptom. Disable it everywhere; nothing else
|
|
||||||
# in that script matters here since _controller is always null without a
|
|
||||||
# real controller ancestor (grip/trigger animation already no-ops).
|
|
||||||
_left_hand.set_physics_process(false)
|
|
||||||
_right_hand.set_physics_process(false)
|
|
||||||
|
|
||||||
if is_multiplayer_authority():
|
|
||||||
var origin := get_tree().get_first_node_in_group("local_xr_origin")
|
|
||||||
if origin:
|
|
||||||
_local_camera = origin.get_node_or_null("XRCamera3D")
|
|
||||||
_local_left_hand = origin.get_node_or_null("XRControllerLeftHand")
|
|
||||||
_local_right_hand = origin.get_node_or_null("XRControllerRightHand")
|
|
||||||
# Every peer's rig is baked at the same spot in the scene; spread
|
|
||||||
# joiners out along X so they don't start stacked on top of each
|
|
||||||
# other. Peer ids from ENet are large effectively-random 32-bit
|
|
||||||
# numbers, so this must be bounded, AND kept well within the
|
|
||||||
# floor's actual footprint (15x15, so ~7.5 units from center) —
|
|
||||||
# a previous version used up to 12 units and could place a
|
|
||||||
# joining player off the edge of the floor.
|
|
||||||
var peer_id := str(name).to_int()
|
|
||||||
if peer_id != 1:
|
|
||||||
var slot := absi(peer_id) % 4
|
|
||||||
origin.position += Vector3((slot - 1.5) * 1.2, 0, 0)
|
|
||||||
# Don't render your own floating head/hands from the inside.
|
|
||||||
_head.visible = false
|
|
||||||
_left_hand.visible = false
|
|
||||||
_right_hand.visible = false
|
|
||||||
else:
|
|
||||||
set_process(false)
|
|
||||||
|
|
||||||
|
|
||||||
func _process(_delta: float) -> void:
|
|
||||||
if _local_camera:
|
|
||||||
_head.global_transform = _local_camera.global_transform
|
|
||||||
if _local_left_hand:
|
|
||||||
_left_hand.global_transform = _local_left_hand.global_transform
|
|
||||||
if _local_right_hand:
|
|
||||||
_right_hand.global_transform = _local_right_hand.global_transform
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
uid://bncuxh7j7ix5q
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
[gd_scene load_steps=5 format=3]
|
|
||||||
|
|
||||||
[ext_resource type="Script" path="res://Player/net_player.gd" id="1_np001"]
|
|
||||||
[ext_resource type="PackedScene" uid="uid://bq86r4yll8po" path="res://addons/godot-xr-tools/hands/scenes/lowpoly/left_fullglove_low.tscn" id="2_np002"]
|
|
||||||
[ext_resource type="PackedScene" uid="uid://xqimcf20s2jp" path="res://addons/godot-xr-tools/hands/scenes/lowpoly/right_fullglove_low.tscn" id="3_np003"]
|
|
||||||
|
|
||||||
[sub_resource type="CapsuleMesh" id="CapsuleMesh_np004"]
|
|
||||||
radius = 0.09
|
|
||||||
height = 0.22
|
|
||||||
|
|
||||||
[sub_resource type="SceneReplicationConfig" id="SceneReplicationConfig_np005"]
|
|
||||||
properties/0/path = NodePath("Head:position")
|
|
||||||
properties/0/spawn = false
|
|
||||||
properties/0/replication_mode = 1
|
|
||||||
properties/1/path = NodePath("Head:quaternion")
|
|
||||||
properties/1/spawn = false
|
|
||||||
properties/1/replication_mode = 1
|
|
||||||
properties/2/path = NodePath("LeftHand:position")
|
|
||||||
properties/2/spawn = false
|
|
||||||
properties/2/replication_mode = 1
|
|
||||||
properties/3/path = NodePath("LeftHand:quaternion")
|
|
||||||
properties/3/spawn = false
|
|
||||||
properties/3/replication_mode = 1
|
|
||||||
properties/4/path = NodePath("RightHand:position")
|
|
||||||
properties/4/spawn = false
|
|
||||||
properties/4/replication_mode = 1
|
|
||||||
properties/5/path = NodePath("RightHand:quaternion")
|
|
||||||
properties/5/spawn = false
|
|
||||||
properties/5/replication_mode = 1
|
|
||||||
|
|
||||||
[node name="NetPlayer" type="Node3D"]
|
|
||||||
script = ExtResource("1_np001")
|
|
||||||
|
|
||||||
[node name="Head" type="MeshInstance3D" parent="."]
|
|
||||||
mesh = SubResource("CapsuleMesh_np004")
|
|
||||||
|
|
||||||
[node name="LeftHand" parent="." instance=ExtResource("2_np002")]
|
|
||||||
|
|
||||||
[node name="RightHand" parent="." instance=ExtResource("3_np003")]
|
|
||||||
|
|
||||||
[node name="Sync" type="MultiplayerSynchronizer" parent="."]
|
|
||||||
root_path = NodePath("..")
|
|
||||||
replication_config = SubResource("SceneReplicationConfig_np005")
|
|
||||||
replication_interval = 0.033
|
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
extends Node3D
|
||||||
|
|
||||||
|
## One instance per connected peer. The owning peer is the multiplayer
|
||||||
|
## authority. The local (authority) player builds the full XR rig from
|
||||||
|
## XROrigin.tscn and feeds its head/hand poses into synced properties; remote
|
||||||
|
## players show a lightweight avatar driven by those synced poses.
|
||||||
|
|
||||||
|
const RIG_SCENE := preload("res://XROrigin.tscn")
|
||||||
|
|
||||||
|
# Synced avatar pose. Authority writes these from the XR trackers each frame;
|
||||||
|
# remotes read them onto the Avatar. net_heartbeat is a monotonic counter used
|
||||||
|
# to confirm replication is live (also handy for debugging).
|
||||||
|
@export var head_xform: Transform3D = Transform3D.IDENTITY
|
||||||
|
@export var left_xform: Transform3D = Transform3D.IDENTITY
|
||||||
|
@export var right_xform: Transform3D = Transform3D.IDENTITY
|
||||||
|
@export var net_heartbeat: int = 0
|
||||||
|
|
||||||
|
var _rig: Node3D
|
||||||
|
var _camera: Node3D
|
||||||
|
var _left: Node3D
|
||||||
|
var _right: Node3D
|
||||||
|
var _is_local := false
|
||||||
|
|
||||||
|
@onready var _avatar: Node3D = $Avatar
|
||||||
|
@onready var _avatar_head: Node3D = $Avatar/Head
|
||||||
|
@onready var _avatar_left: Node3D = $Avatar/LeftHand
|
||||||
|
@onready var _avatar_right: Node3D = $Avatar/RightHand
|
||||||
|
|
||||||
|
|
||||||
|
func _enter_tree() -> void:
|
||||||
|
# The spawner names each player by its owning peer id.
|
||||||
|
set_multiplayer_authority(str(name).to_int())
|
||||||
|
|
||||||
|
|
||||||
|
# (replication config is authored in Player.tscn's MultiplayerSynchronizer)
|
||||||
|
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
_is_local = is_multiplayer_authority()
|
||||||
|
if _is_local:
|
||||||
|
_setup_local()
|
||||||
|
else:
|
||||||
|
_setup_remote()
|
||||||
|
if Engine.has_singleton("NetworkManager") or get_node_or_null("/root/NetworkManager"):
|
||||||
|
NetworkManager.log_line("Player %s ready (authority=%d local=%s)" % [name, get_multiplayer_authority(), str(_is_local)])
|
||||||
|
|
||||||
|
|
||||||
|
func _setup_local() -> void:
|
||||||
|
# We see through the headset; hide our own avatar mesh.
|
||||||
|
_avatar.visible = false
|
||||||
|
_rig = RIG_SCENE.instantiate()
|
||||||
|
add_child(_rig)
|
||||||
|
_camera = _rig.get_node_or_null("XRCamera3D")
|
||||||
|
_left = _rig.get_node_or_null("XRControllerLeftHand")
|
||||||
|
_right = _rig.get_node_or_null("XRControllerRightHand")
|
||||||
|
_enable_xr()
|
||||||
|
|
||||||
|
|
||||||
|
func _enable_xr() -> void:
|
||||||
|
var xr := XRServer.find_interface("OpenXR")
|
||||||
|
if xr and xr.is_initialized():
|
||||||
|
get_viewport().use_xr = true
|
||||||
|
DisplayServer.window_set_vsync_mode(DisplayServer.VSYNC_DISABLED)
|
||||||
|
|
||||||
|
|
||||||
|
func _setup_remote() -> void:
|
||||||
|
_avatar.visible = true
|
||||||
|
|
||||||
|
|
||||||
|
func _process(_delta: float) -> void:
|
||||||
|
if _is_local:
|
||||||
|
if _camera:
|
||||||
|
head_xform = _camera.global_transform
|
||||||
|
left_xform = _left.global_transform
|
||||||
|
right_xform = _right.global_transform
|
||||||
|
net_heartbeat += 1
|
||||||
|
else:
|
||||||
|
_avatar_head.global_transform = head_xform
|
||||||
|
_avatar_left.global_transform = left_xform
|
||||||
|
_avatar_right.global_transform = right_xform
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://ndrfa2xle033
|
||||||
+14
-93
@@ -1,103 +1,24 @@
|
|||||||
class_name CombinableItem
|
class_name CombinableItem
|
||||||
extends Node
|
extends Node
|
||||||
|
|
||||||
const RECIPE_MANAGER = preload("res://RecipeManager.gd")
|
## Identity of this item, referenced by other items' recipes.
|
||||||
|
@export var id: StringName
|
||||||
|
|
||||||
@onready var combine_area_3d: Area3D = $Area3d
|
## Recipes describing what the item holding this component turns into when
|
||||||
@onready var _pickable: XRToolsPickable = get_parent() as XRToolsPickable
|
## another item is combined into it while snapped. Recipes are directional:
|
||||||
|
## only the snapped (base) item's recipes are consulted.
|
||||||
# Guard so a combine only fires once.
|
@export var recipes: Array[CombineRecipe] = []
|
||||||
var _combining: bool = false
|
|
||||||
var _food_item: FoodItem
|
|
||||||
|
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
print("CombinableItem _ready(): ", _pickable.name)
|
if id.is_empty():
|
||||||
_food_item = get_parent().get_node_or_null("FoodItem") as FoodItem
|
push_error("CombinableItem on ", get_parent().name, " has no 'id' set.")
|
||||||
if not _food_item:
|
|
||||||
push_error("CombinableItem is missing FoodItem reference. must be a sibling of a FoodItem on ", get_parent().name, ".")
|
|
||||||
|
|
||||||
if not _pickable:
|
|
||||||
push_error("CombineZone must be a grand child of an XRToolsPickable.")
|
|
||||||
return
|
|
||||||
if not _food_item:
|
|
||||||
push_error("CombineZone requires a FoodItem sibling on ", _pickable.name, ".")
|
|
||||||
return
|
|
||||||
|
|
||||||
# Detect items whether held (layer 17 "Held Objects") or loose
|
|
||||||
# (layer 3 "Pickable Objects"). Don't advertise a layer of our own.
|
|
||||||
combine_area_3d.collision_mask = 0b0000_0000_0000_0001_0000_0000_0000_0100
|
|
||||||
combine_area_3d.collision_layer = 0
|
|
||||||
# Deferred: _ready can run during a physics signal flush (when a combine
|
|
||||||
# spawns the result), where toggling monitoring directly is forbidden.
|
|
||||||
set_deferred("monitoring", false)
|
|
||||||
set_deferred("monitorable", false)
|
|
||||||
|
|
||||||
# Signals
|
|
||||||
_pickable.picked_up.connect(_on_item_picked_up)
|
|
||||||
_pickable.dropped.connect(_on_item_dropped)
|
|
||||||
combine_area_3d.body_entered.connect(_on_body_entered)
|
|
||||||
|
|
||||||
|
|
||||||
# Enable the trigger only while snapped into a snap zone (not hand-held).
|
## Returns the scene this item becomes when combined with [param other_id],
|
||||||
func _on_item_picked_up(_item: Node3D) -> void:
|
## or null if there is no matching recipe.
|
||||||
var by := _pickable.get_picked_up_by()
|
func get_result_for(other_id: StringName) -> PackedScene:
|
||||||
var snapped: bool = by != null and by.has_method("is_xr_class") and by.is_xr_class("XRToolsSnapZone")
|
for recipe in recipes:
|
||||||
set_deferred("monitoring", snapped)
|
if recipe and recipe.ingredient_id == other_id:
|
||||||
|
return recipe.result
|
||||||
func _on_item_dropped(_item: Node3D) -> void:
|
|
||||||
set_deferred("monitoring", false)
|
|
||||||
|
|
||||||
# If the other body is a FoodItem, check for a recipe and combine if one exists.
|
|
||||||
# Combining is a server decision (the base item is server-snapped into a zone).
|
|
||||||
func _on_body_entered(body: Node3D) -> void:
|
|
||||||
if not NetworkManager.owns_world():
|
|
||||||
return
|
|
||||||
if _combining or body == _pickable:
|
|
||||||
print("CombinableItem _on_body_entered: other is our own pickable")
|
|
||||||
return
|
|
||||||
|
|
||||||
var other := _find_food_item(body)
|
|
||||||
if not other:
|
|
||||||
print("CombinableItem _on_body_entered: other is not a foodItem")
|
|
||||||
return
|
|
||||||
|
|
||||||
var result: PackedScene = RECIPE_MANAGER.get_combination_result(_food_item.id, other.id)
|
|
||||||
if not result:
|
|
||||||
print("CombinableItem _on_body_entered: There is no recipe for %s + %s" % [_food_item.id, other.id])
|
|
||||||
return
|
|
||||||
|
|
||||||
_combine(body, result)
|
|
||||||
|
|
||||||
# Instantiate the result of combination and free the two ingredient items
|
|
||||||
func _combine(other_body: Node3D, result: PackedScene) -> void:
|
|
||||||
print("CombinableItem _combine: combining %s + %s into %s" % [_food_item.id, _find_food_item(other_body).id, result.resource_path])
|
|
||||||
|
|
||||||
# Get Snapzone
|
|
||||||
var snap_zone := _pickable.get_picked_up_by()
|
|
||||||
if not snap_zone or not snap_zone.has_method("pick_up_object"):
|
|
||||||
return
|
|
||||||
|
|
||||||
# Spawn the result through the server (so it replicates to every peer,
|
|
||||||
# including late joiners) at the base item's location, in world space.
|
|
||||||
var base_transform := _pickable.global_transform
|
|
||||||
var result_instance: Node3D = NetworkManager.spawn_item(result.resource_path, base_transform)
|
|
||||||
|
|
||||||
# Free the pickable / root of this item and consume the incoming item.
|
|
||||||
snap_zone.drop_object()
|
|
||||||
NetworkManager.despawn_item(_pickable)
|
|
||||||
other_body.drop()
|
|
||||||
NetworkManager.despawn_item(other_body)
|
|
||||||
|
|
||||||
# Snap the result into the now-empty zone.
|
|
||||||
snap_zone.pick_up_object(result_instance)
|
|
||||||
|
|
||||||
|
|
||||||
# Find a FoodItem among the direct children of [param node].
|
|
||||||
func _find_food_item(node: Node) -> FoodItem:
|
|
||||||
if not node:
|
|
||||||
return null
|
|
||||||
for child in node.get_children():
|
|
||||||
if child is FoodItem:
|
|
||||||
return child
|
|
||||||
return null
|
return null
|
||||||
|
|||||||
@@ -1,14 +1,19 @@
|
|||||||
[gd_scene format=3 uid="uid://3lr2dhy62rhk"]
|
[gd_scene format=3 uid="uid://3lr2dhy62rhk"]
|
||||||
|
|
||||||
[ext_resource type="Script" uid="uid://dounic663dn5q" path="res://Prefabs/combinable_item.gd" id="1_q21ti"]
|
[ext_resource type="Script" uid="uid://dounic663dn5q" path="res://Prefabs/combinable_item.gd" id="1_q21ti"]
|
||||||
|
[ext_resource type="Script" uid="uid://coidnv8b2yvxr" path="res://Prefabs/combine_recipe.gd" id="2_anbu7"]
|
||||||
|
[ext_resource type="Script" uid="uid://e3im02nq5cye" path="res://Prefabs/combine_zone.gd" id="4_0om48"]
|
||||||
|
|
||||||
[sub_resource type="SphereShape3D" id="SphereShape3D_o1b3t"]
|
[sub_resource type="BoxShape3D" id="BoxShape3D_combine"]
|
||||||
radius = 0.2
|
size = Vector3(0.16, 0.16, 0.16)
|
||||||
|
|
||||||
[node name="CombinableItem" type="Node3D" unique_id=996936271]
|
[node name="CombinableItem" type="Node3D" unique_id=996936271]
|
||||||
script = ExtResource("1_q21ti")
|
script = ExtResource("1_q21ti")
|
||||||
|
id = &"some_food_item"
|
||||||
|
recipes = Array[ExtResource("2_anbu7")]([null])
|
||||||
|
|
||||||
[node name="Area3d" type="Area3D" parent="." unique_id=1514178016]
|
[node name="CombineZone" type="Area3D" parent="." unique_id=1514178016]
|
||||||
|
script = ExtResource("4_0om48")
|
||||||
|
|
||||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="Area3d" unique_id=706892516]
|
[node name="CollisionShape3D" type="CollisionShape3D" parent="CombineZone" unique_id=706892516]
|
||||||
shape = SubResource("SphereShape3D_o1b3t")
|
shape = SubResource("BoxShape3D_combine")
|
||||||
|
|||||||
@@ -0,0 +1,108 @@
|
|||||||
|
class_name CombineZone
|
||||||
|
extends Area3D
|
||||||
|
|
||||||
|
## Trigger area that lets a snapped item combine with another item pushed into
|
||||||
|
## it. The zone only monitors while its owning item is held by an
|
||||||
|
## [XRToolsSnapZone]; when an item carrying a matching [CombinableItem.id]
|
||||||
|
## enters, the snapped (base) item transforms into the recipe result and the
|
||||||
|
## incoming item is consumed.
|
||||||
|
|
||||||
|
# The pickable this zone belongs to (its parent).
|
||||||
|
@onready var _item: XRToolsPickable = get_parent().get_parent() as XRToolsPickable
|
||||||
|
|
||||||
|
# The base item's recipe data.
|
||||||
|
@onready var _combinable: CombinableItem = _find_combinable(_item)
|
||||||
|
|
||||||
|
# Guard so a combine only fires once.
|
||||||
|
var _combining: bool = false
|
||||||
|
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
# Detect items whether held (layer 17 "Held Objects") or loose
|
||||||
|
# (layer 3 "Pickable Objects"). Don't advertise a layer of our own.
|
||||||
|
collision_mask = 0b0000_0000_0000_0001_0000_0000_0000_0100
|
||||||
|
collision_layer = 0
|
||||||
|
# Deferred: _ready can run during a physics signal flush (when a combine
|
||||||
|
# spawns the result), where toggling monitoring directly is forbidden.
|
||||||
|
set_deferred("monitoring", false)
|
||||||
|
set_deferred("monitorable", false)
|
||||||
|
|
||||||
|
if not _item:
|
||||||
|
push_error("CombineZone must be a grand child of an XRToolsPickable.")
|
||||||
|
return
|
||||||
|
if not _combinable:
|
||||||
|
push_error("CombineZone requires a CombinableItem sibling on ", _item.name, ".")
|
||||||
|
return
|
||||||
|
|
||||||
|
_item.picked_up.connect(_on_item_picked_up)
|
||||||
|
_item.dropped.connect(_on_item_dropped)
|
||||||
|
body_entered.connect(_on_body_entered)
|
||||||
|
|
||||||
|
|
||||||
|
# Enable the trigger only while snapped into a snap zone (not hand-held).
|
||||||
|
func _on_item_picked_up(_pickable: Node3D) -> void:
|
||||||
|
var by := _item.get_picked_up_by()
|
||||||
|
var snapped: bool = by != null and by.has_method("is_xr_class") and by.is_xr_class("XRToolsSnapZone")
|
||||||
|
set_deferred("monitoring", snapped)
|
||||||
|
|
||||||
|
|
||||||
|
func _on_item_dropped(_pickable: Node3D) -> void:
|
||||||
|
set_deferred("monitoring", false)
|
||||||
|
|
||||||
|
|
||||||
|
func _on_body_entered(body: Node3D) -> void:
|
||||||
|
if _combining or body == _item:
|
||||||
|
return
|
||||||
|
|
||||||
|
# Combining is a world-state change: only the server/offline host runs it.
|
||||||
|
# (Clients never have the base item snapped, so their zone won't monitor, but
|
||||||
|
# guard explicitly in case of overlap during authority handoff.)
|
||||||
|
if not NetworkManager.owns_world():
|
||||||
|
return
|
||||||
|
|
||||||
|
var other := _find_combinable(body)
|
||||||
|
if not other:
|
||||||
|
return
|
||||||
|
|
||||||
|
var result: PackedScene = _combinable.get_result_for(other.id)
|
||||||
|
if not result:
|
||||||
|
return
|
||||||
|
|
||||||
|
_combine(body, result)
|
||||||
|
|
||||||
|
|
||||||
|
# Transform the base item into [param result], consuming the incoming item.
|
||||||
|
func _combine(other_body: Node3D, result: PackedScene) -> void:
|
||||||
|
_combining = true
|
||||||
|
|
||||||
|
var snap_zone := _item.get_picked_up_by()
|
||||||
|
if not snap_zone or not snap_zone.has_method("pick_up_object"):
|
||||||
|
push_warning("CombineZone: base item is not held by a snap zone; cannot combine.")
|
||||||
|
_combining = false
|
||||||
|
return
|
||||||
|
|
||||||
|
# Spawn the result (networked) at the base item's location, in world space.
|
||||||
|
var base_transform := _item.global_transform
|
||||||
|
var result_instance := NetworkManager.spawn_item(result.resource_path, base_transform)
|
||||||
|
|
||||||
|
# Free the base item and consume the incoming item.
|
||||||
|
snap_zone.drop_object()
|
||||||
|
_item.queue_free()
|
||||||
|
if other_body.has_method("drop_and_free"):
|
||||||
|
other_body.drop_and_free()
|
||||||
|
else:
|
||||||
|
other_body.queue_free()
|
||||||
|
|
||||||
|
# Snap the result into the now-empty zone.
|
||||||
|
if result_instance:
|
||||||
|
snap_zone.pick_up_object(result_instance)
|
||||||
|
|
||||||
|
|
||||||
|
# Find a CombinableItem among the direct children of [param node].
|
||||||
|
func _find_combinable(node: Node) -> CombinableItem:
|
||||||
|
if not node:
|
||||||
|
return null
|
||||||
|
for child in node.get_children():
|
||||||
|
if child is CombinableItem:
|
||||||
|
return child
|
||||||
|
return null
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://e3im02nq5cye
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
extends Node
|
|
||||||
class_name DespawningItem
|
|
||||||
|
|
||||||
@export var time_to_despawn: float = 8
|
|
||||||
|
|
||||||
# The minimum speed required to reset despawn timer.
|
|
||||||
@export var minimum_speed_square: float = 0.1
|
|
||||||
|
|
||||||
|
|
||||||
@onready var _pickable: XRToolsPickable = get_parent() as XRToolsPickable
|
|
||||||
@onready var _rigid: RigidBody3D = get_parent() as RigidBody3D
|
|
||||||
|
|
||||||
|
|
||||||
var _time_left: float = time_to_despawn
|
|
||||||
|
|
||||||
func _ready() -> void:
|
|
||||||
if not _pickable:
|
|
||||||
push_error("DespawningItem must be a grand child of an XRToolsPickable.")
|
|
||||||
return
|
|
||||||
if not _rigid:
|
|
||||||
push_error("DespawningItem must be a grand child of an RigidBody3D.")
|
|
||||||
return
|
|
||||||
|
|
||||||
|
|
||||||
func _process(delta: float) -> void:
|
|
||||||
print("SpeedSquare: ", _rigid.linear_velocity.length_squared())
|
|
||||||
# if we're held or moving, reset timer and return
|
|
||||||
if _pickable.get_picked_up_by() or _rigid.linear_velocity.length_squared() > pow(minimum_speed_square,2):
|
|
||||||
_time_left = time_to_despawn
|
|
||||||
get_parent().visible = true
|
|
||||||
print("DespawningItem resetting timer: ", get_parent())
|
|
||||||
return
|
|
||||||
|
|
||||||
|
|
||||||
# Count down to zero and despawn
|
|
||||||
_time_left -= delta
|
|
||||||
if _time_left <= 0:
|
|
||||||
print("DespawningItem despawning!" , get_parent())
|
|
||||||
NetworkManager.despawn_item(get_parent())
|
|
||||||
|
|
||||||
# Make item blink in and out before despawning
|
|
||||||
if _time_left < time_to_despawn / 2:
|
|
||||||
get_parent().visible = int(_time_left * 5.0) %2 == 0
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
uid://deyna316ka4xs
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
[gd_scene format=3 uid="uid://b5ukku8i0hilb"]
|
|
||||||
|
|
||||||
[ext_resource type="Script" uid="uid://deyna316ka4xs" path="res://Prefabs/despawning_item.gd" id="1_ayqk8"]
|
|
||||||
|
|
||||||
[node name="DespawningItem" type="Node" unique_id=303090111]
|
|
||||||
script = ExtResource("1_ayqk8")
|
|
||||||
@@ -6,4 +6,3 @@ enum Type { MEAL, SIDE, INGREDIENT, NONE }
|
|||||||
|
|
||||||
@export var id: String
|
@export var id: String
|
||||||
@export var type: Type = Type.NONE
|
@export var type: Type = Type.NONE
|
||||||
@export var sell_value = 1
|
|
||||||
|
|||||||
@@ -4,4 +4,5 @@
|
|||||||
|
|
||||||
[node name="FoodItem" type="Node" unique_id=63948206]
|
[node name="FoodItem" type="Node" unique_id=63948206]
|
||||||
script = ExtResource("1_0na5k")
|
script = ExtResource("1_0na5k")
|
||||||
id = "some_food_id"
|
id = "hamburger"
|
||||||
|
item_type = "Meal"
|
||||||
|
|||||||
@@ -0,0 +1,75 @@
|
|||||||
|
class_name NetPickable
|
||||||
|
extends Node
|
||||||
|
|
||||||
|
## Networks an XRToolsPickable (RigidBody3D). Default authority is the server,
|
||||||
|
## which simulates free items and syncs their transform. Grabbing an item with a
|
||||||
|
## hand transfers authority to the grabbing client (its local kinematic grab
|
||||||
|
## driver then drives the synced transform); releasing returns authority and the
|
||||||
|
## throw velocity to the server. Non-authority peers keep the body frozen and
|
||||||
|
## follow the synced transform, so only one machine ever simulates an item.
|
||||||
|
|
||||||
|
@onready var _item: XRToolsPickable = get_parent() as XRToolsPickable
|
||||||
|
|
||||||
|
var net_held_by := 0 # peer id currently holding (0 = free); kept consistent via NetworkManager
|
||||||
|
var _was_authority := true
|
||||||
|
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
if not _item:
|
||||||
|
push_error("NetPickable must be a child of an XRToolsPickable")
|
||||||
|
return
|
||||||
|
_item.grabbed.connect(_on_grabbed)
|
||||||
|
_item.released.connect(_on_released)
|
||||||
|
_was_authority = _item.is_multiplayer_authority()
|
||||||
|
_apply_authority_state()
|
||||||
|
|
||||||
|
|
||||||
|
## Enable the item only where it is free or where we are its current holder, so
|
||||||
|
## a peer's snap zone / hand never grabs an item another peer is holding. Called
|
||||||
|
## by NetworkManager whenever net_held_by changes. Note: net_held_by is set per
|
||||||
|
## peer by RPC (not by a synchronizer), so the holder keeps its item enabled
|
||||||
|
## while everyone else disables their copy.
|
||||||
|
func apply_held_state() -> void:
|
||||||
|
if not _item:
|
||||||
|
return
|
||||||
|
_item.enabled = net_held_by == 0 or net_held_by == multiplayer.get_unique_id()
|
||||||
|
|
||||||
|
|
||||||
|
func _physics_process(_delta: float) -> void:
|
||||||
|
if not NetworkManager.is_online():
|
||||||
|
return
|
||||||
|
var mine := _item.is_multiplayer_authority()
|
||||||
|
if mine != _was_authority:
|
||||||
|
_was_authority = mine
|
||||||
|
_apply_authority_state()
|
||||||
|
|
||||||
|
|
||||||
|
# Configure physics for whether we own this item or merely mirror it.
|
||||||
|
func _apply_authority_state() -> void:
|
||||||
|
if not _item:
|
||||||
|
return
|
||||||
|
if _item.is_multiplayer_authority():
|
||||||
|
# We own physics: simulate the item whenever it is not held.
|
||||||
|
if not _item.is_picked_up():
|
||||||
|
_item.freeze = false
|
||||||
|
else:
|
||||||
|
# Someone else owns it: follow the synced transform kinematically.
|
||||||
|
_item.freeze = true
|
||||||
|
_item.freeze_mode = RigidBody3D.FREEZE_MODE_KINEMATIC
|
||||||
|
|
||||||
|
|
||||||
|
func _on_grabbed(_pickable: Node3D, by: Node3D) -> void:
|
||||||
|
if not NetworkManager.is_online():
|
||||||
|
return
|
||||||
|
# Only hand grabs transfer authority; snap-zone grabs are server-driven.
|
||||||
|
if not (by is XRToolsFunctionPickup):
|
||||||
|
return
|
||||||
|
NetworkManager.request_item_authority.rpc_id(1, _item.get_path())
|
||||||
|
|
||||||
|
|
||||||
|
func _on_released(_pickable: Node3D, by: Node3D) -> void:
|
||||||
|
if not NetworkManager.is_online():
|
||||||
|
return
|
||||||
|
if not (by is XRToolsFunctionPickup):
|
||||||
|
return
|
||||||
|
NetworkManager.release_item_authority.rpc_id(1, _item.get_path(), _item.linear_velocity, _item.angular_velocity)
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://6n784li8n5ck
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
[gd_scene format=3 uid="uid://mpapt5mkbuao"]
|
|
||||||
|
|
||||||
[sub_resource type="PhysicsMaterial" id="PhysicsMaterial_4m60m"]
|
|
||||||
friction = 0.0
|
|
||||||
bounce = 1.0
|
|
||||||
|
|
||||||
[sub_resource type="SphereShape3D" id="SphereShape3D_nn8tr"]
|
|
||||||
radius = 0.2752769
|
|
||||||
|
|
||||||
[node name="SlideOffDome" type="StaticBody3D" unique_id=1427609426]
|
|
||||||
collision_layer = 7
|
|
||||||
physics_material_override = SubResource("PhysicsMaterial_4m60m")
|
|
||||||
|
|
||||||
[node name="CollisionShape3D2" type="CollisionShape3D" parent="." unique_id=513124640]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.99165964, 0)
|
|
||||||
shape = SubResource("SphereShape3D_nn8tr")
|
|
||||||
@@ -1,341 +0,0 @@
|
|||||||
class_name RecipeManager
|
|
||||||
extends Node
|
|
||||||
|
|
||||||
static var _recipes: Dictionary
|
|
||||||
static var _combining_map: Dictionary
|
|
||||||
static var _cooking_map: Dictionary
|
|
||||||
static var _chopping_map: Dictionary
|
|
||||||
static var _rolling_map: Dictionary
|
|
||||||
static var _augmenting_map: Dictionary
|
|
||||||
static var _scene_paths: Dictionary
|
|
||||||
static var _loaded: bool = false
|
|
||||||
|
|
||||||
static func load_recipes() -> void:
|
|
||||||
if _loaded:
|
|
||||||
return
|
|
||||||
|
|
||||||
var recipe_path := "res://recipes.yaml"
|
|
||||||
if not FileAccess.file_exists(recipe_path):
|
|
||||||
push_error("RecipeManager: recipes.yaml was not found at %s" % recipe_path)
|
|
||||||
return
|
|
||||||
|
|
||||||
var yaml_available := ClassDB.class_exists("YAML")
|
|
||||||
if yaml_available:
|
|
||||||
var result = ClassDB.class_call_static("YAML", "load_file", recipe_path)
|
|
||||||
if result != null and not result.has_error():
|
|
||||||
var data = result.get_data()
|
|
||||||
if typeof(data) != TYPE_DICTIONARY:
|
|
||||||
push_warning("RecipeManager: YAML addon parsed recipes.yaml but returned an unsupported structure")
|
|
||||||
|
|
||||||
_recipes = data
|
|
||||||
_build_scene_paths()
|
|
||||||
_build_combining_map()
|
|
||||||
_build_cooking_map()
|
|
||||||
_build_chopping_map()
|
|
||||||
_build_rolling_map()
|
|
||||||
_build_augmenting_map()
|
|
||||||
_loaded = true
|
|
||||||
|
|
||||||
|
|
||||||
static func get_combination_result(first_id: StringName, second_id: StringName) -> PackedScene:
|
|
||||||
load_recipes()
|
|
||||||
var result_id = _combining_map.get(_make_pair_key(first_id, second_id))
|
|
||||||
if result_id == null:
|
|
||||||
return null
|
|
||||||
return get_item_scene(result_id)
|
|
||||||
|
|
||||||
|
|
||||||
static func get_cooking_result(ingredient_id: StringName) -> String:
|
|
||||||
load_recipes()
|
|
||||||
for cooked_id in _cooking_map.keys():
|
|
||||||
var cook_defs = _cooking_map[cooked_id]
|
|
||||||
# cook_defs may be an Array of recipe dicts (new) or a single dict (backwards compat)
|
|
||||||
if typeof(cook_defs) == TYPE_ARRAY:
|
|
||||||
for cook_def in cook_defs:
|
|
||||||
if cook_def["ingredient"] == ingredient_id:
|
|
||||||
return cooked_id
|
|
||||||
else:
|
|
||||||
var cook_def = cook_defs
|
|
||||||
if cook_def["ingredient"] == ingredient_id:
|
|
||||||
return cooked_id
|
|
||||||
return ""
|
|
||||||
|
|
||||||
|
|
||||||
static func get_cooking_time(ingredient_id: StringName) -> float:
|
|
||||||
load_recipes()
|
|
||||||
for cooked_id in _cooking_map.keys():
|
|
||||||
var cook_defs = _cooking_map[cooked_id]
|
|
||||||
if typeof(cook_defs) == TYPE_ARRAY:
|
|
||||||
for cook_def in cook_defs:
|
|
||||||
if cook_def["ingredient"] == ingredient_id:
|
|
||||||
return cook_def["time"]
|
|
||||||
else:
|
|
||||||
var cook_def = cook_defs
|
|
||||||
if cook_def["ingredient"] == ingredient_id:
|
|
||||||
return cook_def["time"]
|
|
||||||
return 0.0
|
|
||||||
|
|
||||||
|
|
||||||
static func get_item_scene(item_id: StringName) -> PackedScene:
|
|
||||||
load_recipes()
|
|
||||||
var scene_path = _scene_paths.get(str(item_id), "")
|
|
||||||
if typeof(scene_path) != TYPE_STRING or scene_path.is_empty():
|
|
||||||
push_error("RecipeManager: no scene mapping found for item id '%s'" % item_id)
|
|
||||||
return null
|
|
||||||
|
|
||||||
var scene = ResourceLoader.load(scene_path)
|
|
||||||
if not scene:
|
|
||||||
push_error("RecipeManager: failed to load scene '%s' for item '%s'" % [scene_path, item_id])
|
|
||||||
return null
|
|
||||||
return scene as PackedScene
|
|
||||||
|
|
||||||
|
|
||||||
static func print_all_recipes() -> void:
|
|
||||||
load_recipes()
|
|
||||||
if not _loaded:
|
|
||||||
print("RecipeManager: could not load recipes.yaml; no recipes printed.")
|
|
||||||
return
|
|
||||||
|
|
||||||
if _combining_map.is_empty():
|
|
||||||
print("RecipeManager: no combining recipes found")
|
|
||||||
return
|
|
||||||
|
|
||||||
print("#### RecipeManager: Loaded recipes ####")
|
|
||||||
_print_combining_recipes()
|
|
||||||
print("")
|
|
||||||
_print_cooking_recipes()
|
|
||||||
print("")
|
|
||||||
_print_chopping_recipes()
|
|
||||||
print("")
|
|
||||||
_print_rolling_recipes()
|
|
||||||
print("")
|
|
||||||
_print_augmenting_recipes()
|
|
||||||
|
|
||||||
static func _print_combining_recipes() -> void:
|
|
||||||
for pair_key in _combining_map.keys():
|
|
||||||
var result_id = _combining_map[pair_key]
|
|
||||||
var key_str = str(pair_key)
|
|
||||||
var separator_index = key_str.find("|")
|
|
||||||
if separator_index == -1:
|
|
||||||
print("RecipeManager: invalid combining map key '%s'" % key_str)
|
|
||||||
continue
|
|
||||||
|
|
||||||
var first = key_str.substr(0, separator_index)
|
|
||||||
var second = key_str.substr(separator_index + 1, key_str.length() - separator_index - 1)
|
|
||||||
print(" %s <-combine-- %s + %s" % [result_id, first, second])
|
|
||||||
|
|
||||||
|
|
||||||
static func _print_cooking_recipes() -> void:
|
|
||||||
for cooked_id in _cooking_map.keys():
|
|
||||||
var cook_defs = _cooking_map[cooked_id]
|
|
||||||
if typeof(cook_defs) == TYPE_ARRAY:
|
|
||||||
for cook_def in cook_defs:
|
|
||||||
print(" %s <-cook-- %s - time: %.1f" % [cooked_id, cook_def["ingredient"], cook_def["time"]])
|
|
||||||
else:
|
|
||||||
var cook_def = cook_defs
|
|
||||||
print(" %s <-cook-- %s - time: %.1f" % [cooked_id, cook_def["ingredient"], cook_def["time"]])
|
|
||||||
|
|
||||||
|
|
||||||
static func _print_chopping_recipes() -> void:
|
|
||||||
for chopped_id in _chopping_map.keys():
|
|
||||||
var chop_def = _chopping_map[chopped_id]
|
|
||||||
print(" %s <-chop-- %s - work: %.1f" % [chopped_id, chop_def["ingredient"], chop_def["work"]])
|
|
||||||
|
|
||||||
|
|
||||||
static func _print_rolling_recipes() -> void:
|
|
||||||
for rolled_id in _rolling_map.keys():
|
|
||||||
var roll_def = _rolling_map[rolled_id]
|
|
||||||
print(" %s <-roll-- %s - work: %.1f" % [rolled_id, roll_def["ingredient"], roll_def["work"]])
|
|
||||||
|
|
||||||
|
|
||||||
static func _print_augmenting_recipes() -> void:
|
|
||||||
for target_id in _augmenting_map.keys():
|
|
||||||
var augment_def = _augmenting_map[target_id]
|
|
||||||
for ingredient_id in augment_def.keys():
|
|
||||||
var attr_key = augment_def[ingredient_id]
|
|
||||||
print(" %s <-augment-- %s adds attribute '%s'" % [target_id, ingredient_id, attr_key])
|
|
||||||
|
|
||||||
|
|
||||||
static func _build_scene_paths() -> void:
|
|
||||||
_scene_paths.clear()
|
|
||||||
var items = _recipes.get("items", {})
|
|
||||||
if typeof(items) != TYPE_DICTIONARY:
|
|
||||||
return
|
|
||||||
for item_id in items.keys():
|
|
||||||
var item_def = items[item_id]
|
|
||||||
if typeof(item_def) != TYPE_DICTIONARY:
|
|
||||||
continue
|
|
||||||
var scene_path = item_def.get("scene", "")
|
|
||||||
if typeof(scene_path) == TYPE_STRING and not scene_path.is_empty():
|
|
||||||
_scene_paths[str(item_id)] = scene_path
|
|
||||||
|
|
||||||
|
|
||||||
# Reads strucure into _combining_map:
|
|
||||||
# combining:
|
|
||||||
# hamburger:
|
|
||||||
# - [cooked_burger, burger_buns]
|
|
||||||
static func _build_combining_map() -> void:
|
|
||||||
_combining_map.clear()
|
|
||||||
var combining = _recipes.get("combining", {})
|
|
||||||
for result_id in combining.keys():
|
|
||||||
var recipe_entries = _get_recipe_entries(combining[result_id])
|
|
||||||
if recipe_entries.is_empty():
|
|
||||||
push_error("RecipeManager: combining recipe '%s' must contain at least one valid recipe" % result_id)
|
|
||||||
continue
|
|
||||||
for recipe in recipe_entries:
|
|
||||||
var first = StringName(recipe[0])
|
|
||||||
var second = StringName(recipe[1])
|
|
||||||
var key = _make_pair_key(first, second)
|
|
||||||
_combining_map[key] = result_id
|
|
||||||
|
|
||||||
|
|
||||||
static func _get_recipe_entries(recipe_value: Variant) -> Array:
|
|
||||||
var recipes: Array = []
|
|
||||||
if typeof(recipe_value) != TYPE_ARRAY:
|
|
||||||
return recipes
|
|
||||||
if recipe_value.is_empty():
|
|
||||||
return recipes
|
|
||||||
if typeof(recipe_value[0]) == TYPE_ARRAY:
|
|
||||||
for recipe in recipe_value:
|
|
||||||
if typeof(recipe) == TYPE_ARRAY and recipe.size() == 2:
|
|
||||||
recipes.append(recipe)
|
|
||||||
else:
|
|
||||||
if recipe_value.size() == 2:
|
|
||||||
recipes.append(recipe_value)
|
|
||||||
return recipes
|
|
||||||
|
|
||||||
|
|
||||||
static func _make_pair_key(first_id: StringName, second_id: StringName) -> StringName:
|
|
||||||
if str(first_id) <= str(second_id):
|
|
||||||
return StringName(str(first_id) + "|" + str(second_id))
|
|
||||||
return StringName(str(second_id) + "|" + str(first_id))
|
|
||||||
|
|
||||||
|
|
||||||
# Reads structure into _cooking_map:
|
|
||||||
# cooking:
|
|
||||||
# cooked_burger:
|
|
||||||
# ingredient: raw_burger
|
|
||||||
# time: 3
|
|
||||||
# or allowing multiple recipes for the same cooked item:
|
|
||||||
# charcoal:
|
|
||||||
# - ingredient: cube
|
|
||||||
# time: 1
|
|
||||||
# - ingredient: some_other
|
|
||||||
# time: 2
|
|
||||||
static func _build_cooking_map() -> void:
|
|
||||||
_cooking_map.clear()
|
|
||||||
var cooking = _recipes.get("cooking", {})
|
|
||||||
if typeof(cooking) != TYPE_DICTIONARY:
|
|
||||||
return
|
|
||||||
for cooked_id in cooking.keys():
|
|
||||||
var cook_val = cooking[cooked_id]
|
|
||||||
var entries: Array = []
|
|
||||||
if typeof(cook_val) == TYPE_ARRAY:
|
|
||||||
for entry in cook_val:
|
|
||||||
if typeof(entry) != TYPE_DICTIONARY:
|
|
||||||
push_error("RecipeManager: cooking recipe for '%s' contains a non-dictionary entry" % cooked_id)
|
|
||||||
continue
|
|
||||||
entries.append(entry)
|
|
||||||
elif typeof(cook_val) == TYPE_DICTIONARY:
|
|
||||||
entries.append(cook_val)
|
|
||||||
else:
|
|
||||||
push_error("RecipeManager: cooking recipe for '%s' must be a dictionary or array of dictionaries" % cooked_id)
|
|
||||||
continue
|
|
||||||
|
|
||||||
var parsed_entries: Array = []
|
|
||||||
for cook_def in entries:
|
|
||||||
var ingredient = cook_def.get("ingredient", "")
|
|
||||||
if typeof(ingredient) != TYPE_STRING or str(ingredient).is_empty():
|
|
||||||
push_error("RecipeManager: cooking recipe '%s' missing a valid 'ingredient' field" % cooked_id)
|
|
||||||
continue
|
|
||||||
var time_val = cook_def.get("time", null)
|
|
||||||
if typeof(time_val) != TYPE_INT and typeof(time_val) != TYPE_FLOAT:
|
|
||||||
push_error("RecipeManager: cooking recipe '%s' missing a valid 'time' field" % cooked_id)
|
|
||||||
continue
|
|
||||||
parsed_entries.append({"ingredient": StringName(str(ingredient)), "time": float(time_val)})
|
|
||||||
|
|
||||||
if not parsed_entries.is_empty():
|
|
||||||
_cooking_map[StringName(cooked_id)] = parsed_entries
|
|
||||||
|
|
||||||
|
|
||||||
# Reads structure into _chopping_map:
|
|
||||||
# chopping:
|
|
||||||
# chopped_onion:
|
|
||||||
# ingredient: onion
|
|
||||||
# work: 2
|
|
||||||
static func _build_chopping_map() -> void:
|
|
||||||
_chopping_map.clear()
|
|
||||||
var chopping = _recipes.get("chopping", {})
|
|
||||||
if typeof(chopping) != TYPE_DICTIONARY:
|
|
||||||
return
|
|
||||||
for chopped_id in chopping.keys():
|
|
||||||
var chop_def = chopping[chopped_id]
|
|
||||||
if typeof(chop_def) != TYPE_DICTIONARY:
|
|
||||||
push_error("RecipeManager: chopping recipe for '%s' must be a dictionary" % chopped_id)
|
|
||||||
continue
|
|
||||||
var ingredient = chop_def.get("ingredient", "")
|
|
||||||
if typeof(ingredient) != TYPE_STRING or str(ingredient).is_empty():
|
|
||||||
push_error("RecipeManager: chopping recipe '%s' missing a valid 'ingredient' field" % chopped_id)
|
|
||||||
continue
|
|
||||||
var work_val = chop_def.get("work", null)
|
|
||||||
if typeof(work_val) != TYPE_INT and typeof(work_val) != TYPE_FLOAT:
|
|
||||||
push_error("RecipeManager: chopping recipe '%s' missing a valid 'work' field" % chopped_id)
|
|
||||||
continue
|
|
||||||
# store chopped item -> { ingredient: StringName, work: float }
|
|
||||||
_chopping_map[StringName(chopped_id)] = {"ingredient": StringName(str(ingredient)), "work": float(work_val)}
|
|
||||||
|
|
||||||
|
|
||||||
# Reads structure into _rolling_map:
|
|
||||||
# rolling:
|
|
||||||
# pie_base:
|
|
||||||
# ingredient: dough
|
|
||||||
# work: 80
|
|
||||||
static func _build_rolling_map() -> void:
|
|
||||||
_rolling_map.clear()
|
|
||||||
var rolling = _recipes.get("rolling", {})
|
|
||||||
if typeof(rolling) != TYPE_DICTIONARY:
|
|
||||||
return
|
|
||||||
for rolled_id in rolling.keys():
|
|
||||||
var roll_def = rolling[rolled_id]
|
|
||||||
if typeof(roll_def) != TYPE_DICTIONARY:
|
|
||||||
push_error("RecipeManager: rolling recipe for '%s' must be a dictionary" % rolled_id)
|
|
||||||
continue
|
|
||||||
var ingredient = roll_def.get("ingredient", "")
|
|
||||||
if typeof(ingredient) != TYPE_STRING or str(ingredient).is_empty():
|
|
||||||
push_error("RecipeManager: rolling recipe '%s' missing a valid 'ingredient' field" % rolled_id)
|
|
||||||
continue
|
|
||||||
var work_val = roll_def.get("work", null)
|
|
||||||
if typeof(work_val) != TYPE_INT and typeof(work_val) != TYPE_FLOAT:
|
|
||||||
push_error("RecipeManager: rolling recipe '%s' missing a valid 'work' field" % rolled_id)
|
|
||||||
continue
|
|
||||||
# store rolled item -> { ingredient: StringName, work: float }
|
|
||||||
_rolling_map[StringName(rolled_id)] = {"ingredient": StringName(str(ingredient)), "work": float(work_val)}
|
|
||||||
|
|
||||||
|
|
||||||
# Reads structure into _augmenting_map:
|
|
||||||
# augmenting: # Process of adding an item onto another without changing it's type, but toggling attributes.
|
|
||||||
# cooked_burger:
|
|
||||||
# has_tomato: sliced_tomato
|
|
||||||
# has_cheese: cheese
|
|
||||||
static func _build_augmenting_map() -> void:
|
|
||||||
_augmenting_map.clear()
|
|
||||||
var augmenting = _recipes.get("augmenting", {})
|
|
||||||
if typeof(augmenting) != TYPE_DICTIONARY:
|
|
||||||
return
|
|
||||||
for target_id in augmenting.keys():
|
|
||||||
var augment_def = augmenting[target_id]
|
|
||||||
if typeof(augment_def) != TYPE_DICTIONARY:
|
|
||||||
push_error("RecipeManager: augmenting recipe for '%s' must be a dictionary" % target_id)
|
|
||||||
continue
|
|
||||||
var map: Dictionary = {}
|
|
||||||
for attr_key in augment_def.keys():
|
|
||||||
var ingredient = augment_def[attr_key]
|
|
||||||
if typeof(ingredient) != TYPE_STRING or str(ingredient).is_empty():
|
|
||||||
push_error("RecipeManager: augmenting recipe '%s' has invalid ingredient for '%s'" % [target_id, attr_key])
|
|
||||||
continue
|
|
||||||
# store ingredient -> attribute_key (e.g. sliced_tomato -> has_tomato)
|
|
||||||
map[StringName(str(ingredient))] = StringName(str(attr_key))
|
|
||||||
if not map.is_empty():
|
|
||||||
_augmenting_map[StringName(target_id)] = map
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
uid://cuo88u56uqwuy
|
|
||||||
@@ -1,68 +0,0 @@
|
|||||||
# RecipeManager
|
|
||||||
|
|
||||||
## Overview
|
|
||||||
|
|
||||||
`RecipeManager` is a static Godot class that centralizes recipe data for food item combinations and allows runtime lookup of result scenes.
|
|
||||||
|
|
||||||
The manager loads a single YAML file at startup: `res://recipes.yaml`, using the installed `addons/yaml` addon.
|
|
||||||
|
|
||||||
## Responsibilities
|
|
||||||
|
|
||||||
- Load recipe definitions from `recipes.yaml`.
|
|
||||||
- Provide symmetric lookups for two-item combining recipes so `A + B` and `B + A` map to the same result.
|
|
||||||
- Resolve item IDs to their corresponding scene resources.
|
|
||||||
- Print all loaded combining recipes when the application starts.
|
|
||||||
|
|
||||||
## Data structure in `recipes.yaml`
|
|
||||||
|
|
||||||
The recipe YAML file contains two top-level sections:
|
|
||||||
|
|
||||||
- `items`: maps item IDs to their scene path and optional metadata.
|
|
||||||
- `combining`: maps result item IDs to one or more recipe pairs.
|
|
||||||
|
|
||||||
Example structure:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
items:
|
|
||||||
hamburger:
|
|
||||||
scene: res://Items/hamburger.tscn
|
|
||||||
type: meal
|
|
||||||
burger_buns:
|
|
||||||
scene: res://Items/BurgerBuns.tscn
|
|
||||||
type: ingredient
|
|
||||||
|
|
||||||
combining:
|
|
||||||
hamburger:
|
|
||||||
- [cooked_burger, burger_buns]
|
|
||||||
- [charcoal, charcoal]
|
|
||||||
charcoal:
|
|
||||||
- [cube, cube]
|
|
||||||
```
|
|
||||||
|
|
||||||
### `items`
|
|
||||||
|
|
||||||
Each entry under `items` uses the item ID as the key.
|
|
||||||
The manager reads the `scene` field for each item and uses it to resolve the packed scene for recipe results.
|
|
||||||
|
|
||||||
### `combining`
|
|
||||||
|
|
||||||
Each entry under `combining` represents a result item ID, and its value is a list of recipe pairs.
|
|
||||||
Each recipe pair is a two-item array of ingredient IDs.
|
|
||||||
This allows a single result item to have multiple valid recipes.
|
|
||||||
|
|
||||||
The manager normalizes each ingredient pair using a sorted key string internally, so lookups are symmetric.
|
|
||||||
|
|
||||||
## Runtime behavior
|
|
||||||
|
|
||||||
- `FoodItem.id` is used when combining items to look up the recipe result.
|
|
||||||
- `RecipeManager.get_combination(first_id, second_id)` computes a canonical key for the pair and returns the resulting item's scene.
|
|
||||||
- On startup, `main.gd` calls `RecipeManager.print_all_recipes()`, which logs each combining recipe in the form:
|
|
||||||
|
|
||||||
`ingredient_a + ingredient_b -> result_id`
|
|
||||||
|
|
||||||
## Notes
|
|
||||||
|
|
||||||
- `RecipeManager` prefers the installed YAML addon to parse `recipes.yaml` when it is available.
|
|
||||||
- If the addon is unavailable in the current runtime, the manager falls back to a lightweight built-in parser for the simple `items`/`combining` file format.
|
|
||||||
- Scene paths now live in the YAML data instead of being hardcoded in the manager.
|
|
||||||
- Because `RecipeManager` is static, it can be used from any script without creating an instance.
|
|
||||||
@@ -1,197 +0,0 @@
|
|||||||
[gd_scene format=3 uid="uid://22shbqdvnwgo"]
|
|
||||||
|
|
||||||
[ext_resource type="Script" uid="uid://b4ldkd3ngs0vp" path="res://main.gd" id="1_m3h4l"]
|
|
||||||
[ext_resource type="PackedScene" uid="uid://j5s5wus7tuhb" path="res://XROrigin.tscn" id="2_8pfaf"]
|
|
||||||
[ext_resource type="Material" uid="uid://cmia50cfqxxo4" path="res://Textures/dev_material_3d.tres" id="3_gatbn"]
|
|
||||||
[ext_resource type="PackedScene" uid="uid://j7caslh27nor" path="res://Stations/Hob.tscn" id="4_3lufs"]
|
|
||||||
[ext_resource type="Sky" uid="uid://c1abtpwhdm2d5" path="res://Textures/sky/NightSkyHDRI009_16K.tres" id="5_kh26v"]
|
|
||||||
[ext_resource type="PackedScene" uid="uid://c0lknik4noobs" path="res://Items/BurgerBuns.tscn" id="6_kwbxo"]
|
|
||||||
[ext_resource type="PackedScene" uid="uid://c6rift56ql3f8" path="res://Stations/BurgerBunsDispenser.tscn" id="7_tejmp"]
|
|
||||||
[ext_resource type="PackedScene" uid="uid://bp3v1jl8pctro" path="res://Containers/plate.tscn" id="8_xcnr4"]
|
|
||||||
[ext_resource type="PackedScene" uid="uid://dpot5qie20vf6" path="res://Items/burger.tscn" id="9_rwx83"]
|
|
||||||
[ext_resource type="PackedScene" uid="uid://b3m2ag8g5rj4r" path="res://Items/hamburger.tscn" id="10_waew8"]
|
|
||||||
[ext_resource type="PackedScene" uid="uid://e4i6o5oriecx" path="res://Items/PickupCube.tscn" id="11_8wetd"]
|
|
||||||
[ext_resource type="PackedScene" uid="uid://dvrk268s7gkxh" path="res://Stations/sink.tscn" id="12_ah4xa"]
|
|
||||||
[ext_resource type="PackedScene" uid="uid://cnjwtnhwh0i8q" path="res://Stations/dirt_station.tscn" id="13_46xi2"]
|
|
||||||
[ext_resource type="PackedScene" uid="uid://cfc4ho67u4r5e" path="res://Items/cooked_burger.tscn" id="14_vftjt"]
|
|
||||||
[ext_resource type="PackedScene" uid="uid://efaec6ymgabo" path="res://Stations/Counter.tscn" id="15_tpcje"]
|
|
||||||
[ext_resource type="PackedScene" uid="uid://caf0xanmxbshy" path="res://Stations/table.tscn" id="16_g2k6a"]
|
|
||||||
[ext_resource type="PackedScene" uid="uid://clujaf3u776a3" path="res://addons/godot-xr-tools/objects/viewport_2d_in_3d.tscn" id="17_gatbn"]
|
|
||||||
[ext_resource type="PackedScene" uid="uid://xtcei2uvd5li" path="res://UI/game_over_panel.tscn" id="18_3lufs"]
|
|
||||||
[ext_resource type="Script" uid="uid://cwijoksyou1ey" path="res://Scenes/GameOvercontroler.gd" id="19_3lufs"]
|
|
||||||
|
|
||||||
[sub_resource type="BoxShape3D" id="BoxShape3D_vlqg6"]
|
|
||||||
size = Vector3(16, 0.1, 16)
|
|
||||||
|
|
||||||
[sub_resource type="BoxMesh" id="BoxMesh_24d3s"]
|
|
||||||
material = ExtResource("3_gatbn")
|
|
||||||
size = Vector3(16, 0.1, 16)
|
|
||||||
|
|
||||||
[sub_resource type="Environment" id="Environment_bvwq1"]
|
|
||||||
background_mode = 2
|
|
||||||
sky = ExtResource("5_kh26v")
|
|
||||||
reflected_light_source = 2
|
|
||||||
ssr_enabled = true
|
|
||||||
ssao_enabled = true
|
|
||||||
ssil_enabled = true
|
|
||||||
sdfgi_enabled = true
|
|
||||||
|
|
||||||
[sub_resource type="BoxShape3D" id="BoxShape3D_24d3s"]
|
|
||||||
size = Vector3(16, 10, 0.1)
|
|
||||||
|
|
||||||
[node name="Main" type="Node3D" unique_id=1312265607]
|
|
||||||
script = ExtResource("1_m3h4l")
|
|
||||||
|
|
||||||
[node name="XROrigin3D" parent="." unique_id=2055526621 instance=ExtResource("2_8pfaf")]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.36171648, 0, 0.81835127)
|
|
||||||
|
|
||||||
[node name="DirectionalLight3D" type="DirectionalLight3D" parent="." unique_id=1376644384]
|
|
||||||
transform = Transform3D(-0.8660254, -0.43301278, 0.24999999, 0.3022632, -0.05510214, 0.9516306, -0.39829266, 0.8997021, 0.17860365, 0, 0, 0)
|
|
||||||
|
|
||||||
[node name="Floor" type="StaticBody3D" parent="." unique_id=122279514]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.05, 0)
|
|
||||||
|
|
||||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="Floor" unique_id=958841648]
|
|
||||||
shape = SubResource("BoxShape3D_vlqg6")
|
|
||||||
|
|
||||||
[node name="MeshInstance3D" type="MeshInstance3D" parent="Floor/CollisionShape3D" unique_id=1939997056]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.00018164515, 0.0006352663, -0.002532661)
|
|
||||||
mesh = SubResource("BoxMesh_24d3s")
|
|
||||||
|
|
||||||
[node name="Hob" parent="." unique_id=1687971542 instance=ExtResource("4_3lufs")]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.29336345, 0.5, -1.484)
|
|
||||||
|
|
||||||
[node name="WorldEnvironment" type="WorldEnvironment" parent="." unique_id=1177077250]
|
|
||||||
environment = SubResource("Environment_bvwq1")
|
|
||||||
|
|
||||||
[node name="BurgerBuns" parent="." unique_id=1088240294 instance=ExtResource("6_kwbxo")]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -1.8162017, 1.6081157, -1.4714175)
|
|
||||||
|
|
||||||
[node name="BurgerBunsDispenser" parent="." unique_id=1720683779 instance=ExtResource("7_tejmp")]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -1.832131, 0.014894962, -1.4813508)
|
|
||||||
|
|
||||||
[node name="Plate" parent="." unique_id=190487773 instance=ExtResource("8_xcnr4")]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -1.5717233, 1.5454081, 1.5373346)
|
|
||||||
|
|
||||||
[node name="burger" parent="." unique_id=1417604760 instance=ExtResource("9_rwx83")]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.6888188, 1.4195822, -1.7110313)
|
|
||||||
|
|
||||||
[node name="burger2" parent="." unique_id=1584460510 instance=ExtResource("9_rwx83")]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.6931299, 1.5300478, -1.71225)
|
|
||||||
|
|
||||||
[node name="burger3" parent="." unique_id=1884095916 instance=ExtResource("9_rwx83")]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.69027674, 1.4969791, -1.7210286)
|
|
||||||
|
|
||||||
[node name="burger4" parent="." unique_id=1844818864 instance=ExtResource("9_rwx83")]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.69134104, 1.4543622, -1.7210286)
|
|
||||||
|
|
||||||
[node name="Hamburger" parent="." unique_id=761091445 instance=ExtResource("10_waew8")]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -1.9352558, 1.623975, 1.2447833)
|
|
||||||
|
|
||||||
[node name="PickableObject" parent="." unique_id=1675596942 instance=ExtResource("11_8wetd")]
|
|
||||||
transform = Transform3D(1, 0, -2.2351742e-08, -2.9802322e-08, 1.0000001, 0, -2.6077032e-08, 1.4901161e-08, 1, 0.6225724, 1.4792972, -1.0473135)
|
|
||||||
|
|
||||||
[node name="PickableObject2" parent="." unique_id=713087634 instance=ExtResource("11_8wetd")]
|
|
||||||
transform = Transform3D(1, 0, -2.2351742e-08, -2.9802322e-08, 1.0000001, -5.293956e-23, -2.6077032e-08, 1.4901161e-08, 1, 0.6359743, 1.4639391, -1.1673055)
|
|
||||||
|
|
||||||
[node name="PickableObject3" parent="." unique_id=879935619 instance=ExtResource("11_8wetd")]
|
|
||||||
transform = Transform3D(1, 0, -2.2351742e-08, -2.9802322e-08, 1.0000001, 0, -2.6077032e-08, 1.4901161e-08, 1, 0.5142721, 1.4792972, -1.0473135)
|
|
||||||
|
|
||||||
[node name="PickableObject4" parent="." unique_id=198541902 instance=ExtResource("11_8wetd")]
|
|
||||||
transform = Transform3D(1, 0, -2.2351742e-08, -2.9802322e-08, 1.0000001, -5.293956e-23, -2.6077032e-08, 1.4901161e-08, 1, 0.5276739, 1.4639391, -1.1673055)
|
|
||||||
|
|
||||||
[node name="Hamburger2" parent="." unique_id=1349934579 instance=ExtResource("10_waew8")]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -1.9857153, 1.5329368, 0.9472374)
|
|
||||||
|
|
||||||
[node name="PickableObject5" parent="." unique_id=1021333509 instance=ExtResource("11_8wetd")]
|
|
||||||
transform = Transform3D(1, 0, -2.2351742e-08, -2.9802322e-08, 1.0000001, 0, -2.6077032e-08, 1.4901161e-08, 1, 0.73287535, 1.4792972, -1.0473135)
|
|
||||||
|
|
||||||
[node name="PickableObject6" parent="." unique_id=1268843669 instance=ExtResource("11_8wetd")]
|
|
||||||
transform = Transform3D(1, 0, -2.2351742e-08, -2.9802322e-08, 1.0000001, -5.293956e-23, -2.6077032e-08, 1.4901161e-08, 1, 0.7462772, 1.4639391, -1.1673055)
|
|
||||||
|
|
||||||
[node name="Sink" parent="." unique_id=2055277359 instance=ExtResource("12_ah4xa")]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 1.3140475, 0.5, -1.4941733)
|
|
||||||
|
|
||||||
[node name="DirtStation" parent="." unique_id=160842153 instance=ExtResource("13_46xi2")]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 2.0864775, 0.5, -1.244947)
|
|
||||||
|
|
||||||
[node name="Plate2" parent="." unique_id=356790445 instance=ExtResource("8_xcnr4")]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -1.5730225, 1.499024, 0.59790254)
|
|
||||||
|
|
||||||
[node name="CookedBurger" parent="." unique_id=1127807542 instance=ExtResource("14_vftjt")]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.30671906, 1.4131018, -1.0928738)
|
|
||||||
|
|
||||||
[node name="CookedBurger2" parent="." unique_id=160088590 instance=ExtResource("14_vftjt")]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.30671906, 1.4496142, -1.0928738)
|
|
||||||
|
|
||||||
[node name="CookedBurger3" parent="." unique_id=992183367 instance=ExtResource("14_vftjt")]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -1.3344773, 1.4398065, -0.7096845)
|
|
||||||
|
|
||||||
[node name="CookedBurger4" parent="." unique_id=1837607086 instance=ExtResource("14_vftjt")]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.30671906, 1.525444, -1.0928738)
|
|
||||||
|
|
||||||
[node name="BurgerBuns2" parent="." unique_id=1210358958 instance=ExtResource("6_kwbxo")]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -1.3596323, 1.4110342, -0.22482127)
|
|
||||||
|
|
||||||
[node name="PickableObject7" parent="." unique_id=641653545 instance=ExtResource("11_8wetd")]
|
|
||||||
transform = Transform3D(1, 0, -2.2351742e-08, -2.9802322e-08, 1.0000001, 0, -2.6077032e-08, 1.4901161e-08, 1, -1.3556751, 1.4792972, 0.28881657)
|
|
||||||
|
|
||||||
[node name="PickableObject8" parent="." unique_id=1733819363 instance=ExtResource("11_8wetd")]
|
|
||||||
transform = Transform3D(1, 0, -2.2351742e-08, -2.9802322e-08, 1.0000001, -5.293956e-23, -2.6077032e-08, 1.4901161e-08, 1, -1.3422732, 1.4639391, 0.16882455)
|
|
||||||
|
|
||||||
[node name="PickableObject9" parent="." unique_id=12419746 instance=ExtResource("11_8wetd")]
|
|
||||||
transform = Transform3D(1, 0, -2.2351742e-08, -2.9802322e-08, 1.0000001, 0, -2.6077032e-08, 1.4901161e-08, 1, -1.4639754, 1.4792972, 0.28881657)
|
|
||||||
|
|
||||||
[node name="PickableObject10" parent="." unique_id=313160217 instance=ExtResource("11_8wetd")]
|
|
||||||
transform = Transform3D(1, 0, -2.2351742e-08, -2.9802322e-08, 1.0000001, -5.293956e-23, -2.6077032e-08, 1.4901161e-08, 1, -1.4505737, 1.4639391, 0.16882455)
|
|
||||||
|
|
||||||
[node name="Counter" parent="." unique_id=1487893288 instance=ExtResource("15_tpcje")]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.7124918, 0.5, -1.4886917)
|
|
||||||
|
|
||||||
[node name="Counter2" parent="." unique_id=368890752 instance=ExtResource("15_tpcje")]
|
|
||||||
transform = Transform3D(-4.371139e-08, 0, 1, 0, 1, 0, -1, 0, -4.371139e-08, -1.7648025, 0.5, -0.4458799)
|
|
||||||
|
|
||||||
[node name="Counter3" parent="." unique_id=1498817646 instance=ExtResource("15_tpcje")]
|
|
||||||
transform = Transform3D(-4.371139e-08, 0, 1, 0, 1, 0, -1, 0, -4.371139e-08, -1.7648025, 0.5, 0.55367994)
|
|
||||||
|
|
||||||
[node name="Counter4" parent="." unique_id=906748771 instance=ExtResource("15_tpcje")]
|
|
||||||
transform = Transform3D(-4.371139e-08, 0, 1, 0, 1, 0, -1, 0, -4.371139e-08, -1.7648025, 0.5, 1.5539298)
|
|
||||||
|
|
||||||
[node name="Table" parent="." unique_id=1863572470 instance=ExtResource("16_g2k6a")]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 2.139665, 0.9030438, 2.2267122)
|
|
||||||
|
|
||||||
[node name="Hamburger3" parent="." unique_id=369573848 instance=ExtResource("10_waew8")]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -1.7201865, 1.5329367, 0.14773655)
|
|
||||||
|
|
||||||
[node name="Plate3" parent="." unique_id=2004250522 instance=ExtResource("8_xcnr4")]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -1.5818124, 1.499024, -0.4634577)
|
|
||||||
|
|
||||||
[node name="StaticBody3D" type="StaticBody3D" parent="." unique_id=315740174]
|
|
||||||
|
|
||||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="StaticBody3D" unique_id=33059670]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 4.689, 8)
|
|
||||||
shape = SubResource("BoxShape3D_24d3s")
|
|
||||||
|
|
||||||
[node name="CollisionShape3D2" type="CollisionShape3D" parent="StaticBody3D" unique_id=2018792171]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 4.689, -8)
|
|
||||||
shape = SubResource("BoxShape3D_24d3s")
|
|
||||||
|
|
||||||
[node name="CollisionShape3D3" type="CollisionShape3D" parent="StaticBody3D" unique_id=757662929]
|
|
||||||
transform = Transform3D(-4.371139e-08, 0, -1, 0, 1, 0, 1, 0, -4.371139e-08, -8, 4.689, 0)
|
|
||||||
shape = SubResource("BoxShape3D_24d3s")
|
|
||||||
|
|
||||||
[node name="CollisionShape3D4" type="CollisionShape3D" parent="StaticBody3D" unique_id=1468386997]
|
|
||||||
transform = Transform3D(-4.371139e-08, 0, -1, 0, 1, 0, 1, 0, -4.371139e-08, 8, 4.689, 0)
|
|
||||||
shape = SubResource("BoxShape3D_24d3s")
|
|
||||||
|
|
||||||
[node name="GameOverPanel" parent="." unique_id=221361954 instance=ExtResource("17_gatbn")]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.46454135, 3.4496074, -1.832967)
|
|
||||||
visible = false
|
|
||||||
scene = ExtResource("18_3lufs")
|
|
||||||
viewport_size = Vector2(900, 600)
|
|
||||||
transparent = 0
|
|
||||||
filter = false
|
|
||||||
scene_properties_keys = PackedStringArray("main_menu_panel.gd")
|
|
||||||
|
|
||||||
[node name="controler" type="Node" parent="GameOverPanel" unique_id=1302491889]
|
|
||||||
script = ExtResource("19_3lufs")
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
extends Node
|
|
||||||
|
|
||||||
|
|
||||||
func _ready() -> void:
|
|
||||||
$"..".visible = false
|
|
||||||
|
|
||||||
# Listen for the game over signal from GameManager
|
|
||||||
Signals.game_over.connect(_on_game_over)
|
|
||||||
|
|
||||||
func _on_game_over() -> void:
|
|
||||||
$"..".visible = true
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
uid://cwijoksyou1ey
|
|
||||||
+81
-81
@@ -4,49 +4,42 @@
|
|||||||
[ext_resource type="PackedScene" uid="uid://j5s5wus7tuhb" path="res://XROrigin.tscn" id="2_o1b3t"]
|
[ext_resource type="PackedScene" uid="uid://j5s5wus7tuhb" path="res://XROrigin.tscn" id="2_o1b3t"]
|
||||||
[ext_resource type="Material" uid="uid://cmia50cfqxxo4" path="res://Textures/dev_material_3d.tres" id="3_irf4n"]
|
[ext_resource type="Material" uid="uid://cmia50cfqxxo4" path="res://Textures/dev_material_3d.tres" id="3_irf4n"]
|
||||||
[ext_resource type="PackedScene" uid="uid://j7caslh27nor" path="res://Stations/Hob.tscn" id="4_ctden"]
|
[ext_resource type="PackedScene" uid="uid://j7caslh27nor" path="res://Stations/Hob.tscn" id="4_ctden"]
|
||||||
|
[ext_resource type="Script" uid="uid://cquqe4f1m1sw6" path="res://addons/godot-xr-tools/objects/snap_zone.gd" id="5_57ppd"]
|
||||||
|
[ext_resource type="PackedScene" uid="uid://e4i6o5oriecx" path="res://Items/PickupCube.tscn" id="6_eoxxy"]
|
||||||
[ext_resource type="Sky" uid="uid://c1abtpwhdm2d5" path="res://Textures/sky/NightSkyHDRI009_16K.tres" id="7_n8fyw"]
|
[ext_resource type="Sky" uid="uid://c1abtpwhdm2d5" path="res://Textures/sky/NightSkyHDRI009_16K.tres" id="7_n8fyw"]
|
||||||
|
[ext_resource type="PackedScene" uid="uid://c0lknik4noobs" path="res://Items/BurgerBuns.tscn" id="8_rraok"]
|
||||||
[ext_resource type="PackedScene" uid="uid://c6rift56ql3f8" path="res://Stations/BurgerBunsDispenser.tscn" id="9_sq0s2"]
|
[ext_resource type="PackedScene" uid="uid://c6rift56ql3f8" path="res://Stations/BurgerBunsDispenser.tscn" id="9_sq0s2"]
|
||||||
[ext_resource type="PackedScene" uid="uid://cwnwo4i28upap" path="res://Stations/raw_burger_dispenser.tscn" id="11_ctden"]
|
[ext_resource type="PackedScene" uid="uid://bp3v1jl8pctro" path="res://Containers/plate.tscn" id="10_ay2w6"]
|
||||||
[ext_resource type="PackedScene" uid="uid://bbg7dwsbxxh1t" path="res://Scenes/cube_side_dispense.tscn" id="12_57ppd"]
|
[ext_resource type="PackedScene" uid="uid://dpot5qie20vf6" path="res://Items/burger.tscn" id="11_qn1ku"]
|
||||||
[ext_resource type="PackedScene" uid="uid://ck5tuftqmyiue" path="res://Stations/plate_dispenser.tscn" id="13_irf4n"]
|
[ext_resource type="PackedScene" uid="uid://b3m2ag8g5rj4r" path="res://Items/hamburger.tscn" id="12_hfwnn"]
|
||||||
[ext_resource type="PackedScene" uid="uid://dvrk268s7gkxh" path="res://Stations/sink.tscn" id="13_o1b3t"]
|
|
||||||
[ext_resource type="PackedScene" uid="uid://clujaf3u776a3" path="res://addons/godot-xr-tools/objects/viewport_2d_in_3d.tscn" id="14_di04w"]
|
[sub_resource type="BoxShape3D" id="BoxShape3D_vlqg6"]
|
||||||
[ext_resource type="PackedScene" uid="uid://cnjwtnhwh0i8q" path="res://Stations/dirt_station.tscn" id="14_irf4n"]
|
size = Vector3(5, 0.1, 5)
|
||||||
[ext_resource type="PackedScene" uid="uid://efaec6ymgabo" path="res://Stations/Counter.tscn" id="15_di04w"]
|
|
||||||
[ext_resource type="PackedScene" uid="uid://xtcei2uvd5li" path="res://UI/game_over_panel.tscn" id="15_eoxxy"]
|
[sub_resource type="BoxMesh" id="BoxMesh_24d3s"]
|
||||||
[ext_resource type="PackedScene" uid="uid://caf0xanmxbshy" path="res://Stations/table.tscn" id="16_di04w"]
|
material = ExtResource("3_irf4n")
|
||||||
[ext_resource type="Script" uid="uid://cwijoksyou1ey" path="res://Scenes/GameOvercontroler.gd" id="16_n8fyw"]
|
size = Vector3(5, 0.1, 5)
|
||||||
|
|
||||||
|
[sub_resource type="BoxShape3D" id="BoxShape3D_24d3s"]
|
||||||
|
|
||||||
|
[sub_resource type="BoxMesh" id="BoxMesh_i5j2u"]
|
||||||
|
|
||||||
|
[sub_resource type="SphereShape3D" id="SphereShape3D_dlkho"]
|
||||||
|
radius = 0.3
|
||||||
|
|
||||||
[sub_resource type="Environment" id="Environment_bvwq1"]
|
[sub_resource type="Environment" id="Environment_bvwq1"]
|
||||||
background_mode = 2
|
background_mode = 2
|
||||||
sky = ExtResource("7_n8fyw")
|
sky = ExtResource("7_n8fyw")
|
||||||
ambient_light_source = 3
|
|
||||||
ambient_light_color = Color(1, 1, 1, 1)
|
|
||||||
ambient_light_sky_contribution = 0.9
|
|
||||||
reflected_light_source = 2
|
reflected_light_source = 2
|
||||||
ssr_enabled = true
|
ssr_enabled = true
|
||||||
ssao_enabled = true
|
ssao_enabled = true
|
||||||
ssil_enabled = true
|
ssil_enabled = true
|
||||||
sdfgi_enabled = true
|
sdfgi_enabled = true
|
||||||
|
|
||||||
[sub_resource type="BoxShape3D" id="BoxShape3D_vlqg6"]
|
|
||||||
size = Vector3(20, 0.1, 20)
|
|
||||||
|
|
||||||
[sub_resource type="BoxMesh" id="BoxMesh_24d3s"]
|
|
||||||
material = ExtResource("3_irf4n")
|
|
||||||
size = Vector3(20, 0.1, 20)
|
|
||||||
|
|
||||||
[sub_resource type="BoxShape3D" id="BoxShape3D_24d3s"]
|
|
||||||
size = Vector3(20, 10, 0.1)
|
|
||||||
|
|
||||||
[node name="Main" type="Node3D" unique_id=1312265607]
|
[node name="Main" type="Node3D" unique_id=1312265607]
|
||||||
script = ExtResource("1_57ppd")
|
script = ExtResource("1_57ppd")
|
||||||
|
|
||||||
[node name="WorldEnvironment" type="WorldEnvironment" parent="." unique_id=1177077250]
|
|
||||||
environment = SubResource("Environment_bvwq1")
|
|
||||||
|
|
||||||
[node name="XROrigin3D" parent="." unique_id=2055526621 instance=ExtResource("2_o1b3t")]
|
[node name="XROrigin3D" parent="." unique_id=2055526621 instance=ExtResource("2_o1b3t")]
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.9667189, 0)
|
|
||||||
|
|
||||||
[node name="DirectionalLight3D" type="DirectionalLight3D" parent="." unique_id=1376644384]
|
[node name="DirectionalLight3D" type="DirectionalLight3D" parent="." unique_id=1376644384]
|
||||||
transform = Transform3D(-0.8660254, -0.43301278, 0.24999999, 0.3022632, -0.05510214, 0.9516306, -0.39829266, 0.8997021, 0.17860365, 0, 0, 0)
|
transform = Transform3D(-0.8660254, -0.43301278, 0.24999999, 0.3022632, -0.05510214, 0.9516306, -0.39829266, 0.8997021, 0.17860365, 0, 0, 0)
|
||||||
@@ -61,72 +54,79 @@ shape = SubResource("BoxShape3D_vlqg6")
|
|||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.00018164515, 0.0006352663, -0.002532661)
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.00018164515, 0.0006352663, -0.002532661)
|
||||||
mesh = SubResource("BoxMesh_24d3s")
|
mesh = SubResource("BoxMesh_24d3s")
|
||||||
|
|
||||||
[node name="InvisibleWalls" type="StaticBody3D" parent="." unique_id=315740174]
|
|
||||||
|
|
||||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="InvisibleWalls" unique_id=33059670]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 4.688614, 8.838269)
|
|
||||||
shape = SubResource("BoxShape3D_24d3s")
|
|
||||||
|
|
||||||
[node name="CollisionShape3D2" type="CollisionShape3D" parent="InvisibleWalls" unique_id=2018792171]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 4.688614, -10.243342)
|
|
||||||
shape = SubResource("BoxShape3D_24d3s")
|
|
||||||
|
|
||||||
[node name="CollisionShape3D3" type="CollisionShape3D" parent="InvisibleWalls" unique_id=757662929]
|
|
||||||
transform = Transform3D(-4.371139e-08, 0, -1, 0, 1, 0, 1, 0, -4.371139e-08, -9.807113, 4.688614, -0.018813243)
|
|
||||||
shape = SubResource("BoxShape3D_24d3s")
|
|
||||||
|
|
||||||
[node name="CollisionShape3D4" type="CollisionShape3D" parent="InvisibleWalls" unique_id=1468386997]
|
|
||||||
transform = Transform3D(-4.371139e-08, 0, -1, 0, 1, 0, 1, 0, -4.371139e-08, 9.934778, 4.297072, -0.018813023)
|
|
||||||
shape = SubResource("BoxShape3D_24d3s")
|
|
||||||
|
|
||||||
[node name="Table" parent="." unique_id=1863572470 instance=ExtResource("16_di04w")]
|
|
||||||
transform = Transform3D(-1, 0, 8.742277e-08, 0, 1, 0, -8.742277e-08, 0, -1, 3.6294794, 0.54177135, 0.0973109)
|
|
||||||
thinking_duration = 35.0
|
|
||||||
primary_duration = 5.0
|
|
||||||
|
|
||||||
[node name="Hob" parent="." unique_id=1687971542 instance=ExtResource("4_ctden")]
|
[node name="Hob" parent="." unique_id=1687971542 instance=ExtResource("4_ctden")]
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.35077858, 0.50655985, -1.2833805)
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.29336345, 0.8981018, -1.484)
|
||||||
|
|
||||||
[node name="Sink" parent="." unique_id=2055277359 instance=ExtResource("13_o1b3t")]
|
[node name="Counter" type="StaticBody3D" parent="." unique_id=1487893288 groups=["station"]]
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.24685252, 0.51461196, -1.2828919)
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.73186195, 0.8981018, -1.484)
|
||||||
|
|
||||||
[node name="DirtStation" parent="." unique_id=160842153 instance=ExtResource("14_irf4n")]
|
[node name="CollisionShape3D" type="CollisionShape3D" parent="Counter" unique_id=692568688]
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.7978771, 0.50655985, -1.2598276)
|
shape = SubResource("BoxShape3D_24d3s")
|
||||||
|
|
||||||
[node name="Counter" parent="." unique_id=1487893288 instance=ExtResource("15_di04w")]
|
[node name="MeshInstance3D" type="MeshInstance3D" parent="Counter/CollisionShape3D" unique_id=127773521]
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.94890714, 0.5115015, -1.3041471)
|
mesh = SubResource("BoxMesh_i5j2u")
|
||||||
|
|
||||||
[node name="Counter2" parent="." unique_id=368890752 instance=ExtResource("15_di04w")]
|
[node name="Label3D" type="Label3D" parent="Counter/CollisionShape3D" unique_id=149978729]
|
||||||
transform = Transform3D(-4.371139e-08, 0, 1, 0, 1, 0, -1, 0, -4.371139e-08, -1.5477214, 0.5115016, -0.1103079)
|
transform = Transform3D(0.9999992, 0, 0, 0, 0.99999946, 0, 0, 0, 0.9999992, 0.002797456, 0.6309581, -0.2812457)
|
||||||
|
text = "Counter"
|
||||||
|
|
||||||
[node name="Counter4" parent="." unique_id=1748373996 instance=ExtResource("15_di04w")]
|
[node name="XRToolsSnapZone" type="Area3D" parent="Counter" unique_id=1647380272 groups=["station"]]
|
||||||
transform = Transform3D(-4.371139e-08, 0, 1, 0, 1, 0, -1, 0, -4.371139e-08, -1.5477214, 0.5115016, -0.70863545)
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.5270121, 0)
|
||||||
|
collision_layer = 65536
|
||||||
|
collision_mask = 65536
|
||||||
|
script = ExtResource("5_57ppd")
|
||||||
|
snap_mode = 1
|
||||||
|
initial_object = NodePath("../../Plate")
|
||||||
|
metadata/_custom_type_script = "uid://cquqe4f1m1sw6"
|
||||||
|
|
||||||
[node name="Counter3" parent="." unique_id=1498817646 instance=ExtResource("15_di04w")]
|
[node name="CollisionShape3D2" type="CollisionShape3D" parent="Counter/XRToolsSnapZone" unique_id=969340130]
|
||||||
transform = Transform3D(-4.371139e-08, 0, 1, 0, 1, 0, -1, 0, -4.371139e-08, -1.5477214, 0.5115016, 0.49258912)
|
transform = Transform3D(0.5, 0, 0, 0, 0.5, 0, 0, 0, 0.5, 0, -0.000975132, 0)
|
||||||
|
shape = SubResource("SphereShape3D_dlkho")
|
||||||
|
|
||||||
[node name="Counter5" parent="Counter3" unique_id=200341072 instance=ExtResource("15_di04w")]
|
[node name="WorldEnvironment" type="WorldEnvironment" parent="." unique_id=1177077250]
|
||||||
transform = Transform3D(-4.371139e-08, 0, -1, 0, 1, 0, 1, 0, -4.371139e-08, 1.8051152, 0, 3.5603657)
|
environment = SubResource("Environment_bvwq1")
|
||||||
|
|
||||||
|
[node name="BurgerBuns" parent="." unique_id=1088240294 instance=ExtResource("8_rraok")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -1.8162017, 1.6081157, -1.4714175)
|
||||||
|
|
||||||
[node name="BurgerBunsDispenser" parent="." unique_id=1720683779 instance=ExtResource("9_sq0s2")]
|
[node name="BurgerBunsDispenser" parent="." unique_id=1720683779 instance=ExtResource("9_sq0s2")]
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -1.5242664, 0.008738995, 1.1073059)
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -1.832131, 0.40028095, -1.4813508)
|
||||||
|
|
||||||
[node name="RawBurgerDispenser" parent="." unique_id=235630131 instance=ExtResource("11_ctden")]
|
[node name="Plate" parent="." unique_id=190487773 instance=ExtResource("10_ay2w6")]
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.8896122, 0.008738995, 1.0872328)
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.72025335, 1.4458435, -1.5107731)
|
||||||
|
|
||||||
[node name="PlateDispenser" parent="." unique_id=710538846 instance=ExtResource("13_irf4n")]
|
[node name="burger" parent="." unique_id=1417604760 instance=ExtResource("11_qn1ku")]
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.26631236, 0.008738995, 1.087036)
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -1.1439226, 1.4195822, -1.2004558)
|
||||||
|
|
||||||
[node name="GameOverPanel" parent="." unique_id=1234658657 instance=ExtResource("14_di04w")]
|
[node name="burger2" parent="." unique_id=1584460510 instance=ExtResource("11_qn1ku")]
|
||||||
transform = Transform3D(-4.371139e-08, 0, 1, 0, 1, 0, -1, 0, -4.371139e-08, -2.0281777, 2.8122003, 0)
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -1.1396115, 1.5300478, -1.2016745)
|
||||||
scene = ExtResource("15_eoxxy")
|
|
||||||
viewport_size = Vector2(900, 600)
|
|
||||||
transparent = 0
|
|
||||||
filter = false
|
|
||||||
scene_properties_keys = PackedStringArray("game_over_panel.gd")
|
|
||||||
|
|
||||||
[node name="controler" type="Node" parent="GameOverPanel" unique_id=803158176]
|
[node name="burger3" parent="." unique_id=1884095916 instance=ExtResource("11_qn1ku")]
|
||||||
script = ExtResource("16_n8fyw")
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -1.1424646, 1.4969791, -1.210453)
|
||||||
|
|
||||||
[node name="CubeSideDispenser2" parent="." unique_id=200950572 instance=ExtResource("12_57ppd")]
|
[node name="burger4" parent="." unique_id=1844818864 instance=ExtResource("11_qn1ku")]
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.35154933, 0, 1.1119425)
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -1.1414003, 1.4543622, -1.210453)
|
||||||
|
|
||||||
|
[node name="Hamburger" parent="." unique_id=761091445 instance=ExtResource("12_hfwnn")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.18456237, 1.5438088, -1.3716147)
|
||||||
|
|
||||||
|
[node name="PickableObject" parent="." unique_id=1675596942 instance=ExtResource("6_eoxxy")]
|
||||||
|
transform = Transform3D(1, 0, -2.2351742e-08, -2.9802322e-08, 1.0000001, 0, -2.6077032e-08, 1.4901161e-08, 1, -0.042440414, 1.4792972, -1.0473135)
|
||||||
|
|
||||||
|
[node name="PickableObject2" parent="." unique_id=713087634 instance=ExtResource("6_eoxxy")]
|
||||||
|
transform = Transform3D(1, 0, -2.2351742e-08, -2.9802322e-08, 1.0000001, -5.293956e-23, -2.6077032e-08, 1.4901161e-08, 1, -0.029038578, 1.4639391, -1.1673055)
|
||||||
|
|
||||||
|
[node name="PickableObject3" parent="." unique_id=879935619 instance=ExtResource("6_eoxxy")]
|
||||||
|
transform = Transform3D(1, 0, -2.2351742e-08, -2.9802322e-08, 1.0000001, 0, -2.6077032e-08, 1.4901161e-08, 1, -0.15074077, 1.4792972, -1.0473135)
|
||||||
|
|
||||||
|
[node name="PickableObject4" parent="." unique_id=198541902 instance=ExtResource("6_eoxxy")]
|
||||||
|
transform = Transform3D(1, 0, -2.2351742e-08, -2.9802322e-08, 1.0000001, -5.293956e-23, -2.6077032e-08, 1.4901161e-08, 1, -0.13733894, 1.4639391, -1.1673055)
|
||||||
|
|
||||||
|
[node name="Hamburger2" parent="." unique_id=1349934579 instance=ExtResource("12_hfwnn")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.15603885, 1.5329368, -1.6386203)
|
||||||
|
|
||||||
|
[node name="PickableObject5" parent="." unique_id=1021333509 instance=ExtResource("6_eoxxy")]
|
||||||
|
transform = Transform3D(1, 0, -2.2351742e-08, -2.9802322e-08, 1.0000001, 0, -2.6077032e-08, 1.4901161e-08, 1, 0.06786254, 1.4792972, -1.0473135)
|
||||||
|
|
||||||
|
[node name="PickableObject6" parent="." unique_id=1268843669 instance=ExtResource("6_eoxxy")]
|
||||||
|
transform = Transform3D(1, 0, -2.2351742e-08, -2.9802322e-08, 1.0000001, -5.293956e-23, -2.6077032e-08, 1.4901161e-08, 1, 0.08126438, 1.4639391, -1.1673055)
|
||||||
|
|||||||
@@ -1,72 +0,0 @@
|
|||||||
[gd_scene format=3 uid="uid://bbg7dwsbxxh1t"]
|
|
||||||
|
|
||||||
[ext_resource type="Script" uid="uid://0y6wnjcsum6" path="res://Stations/item_dispenser.gd" id="1_4m60m"]
|
|
||||||
[ext_resource type="PackedScene" uid="uid://e4i6o5oriecx" path="res://Items/PickupCube.tscn" id="2_nn8tr"]
|
|
||||||
[ext_resource type="Script" uid="uid://cquqe4f1m1sw6" path="res://addons/godot-xr-tools/objects/snap_zone.gd" id="3_ahn1e"]
|
|
||||||
[ext_resource type="PackedScene" uid="uid://mpapt5mkbuao" path="res://Prefabs/slide_off_dome.tscn" id="4_nn8tr"]
|
|
||||||
|
|
||||||
[sub_resource type="SphereShape3D" id="SphereShape3D_xmbo2"]
|
|
||||||
radius = 0.3
|
|
||||||
|
|
||||||
[sub_resource type="CylinderShape3D" id="CylinderShape3D_24d3s"]
|
|
||||||
radius = 0.29541016
|
|
||||||
|
|
||||||
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_24d3s"]
|
|
||||||
albedo_color = Color(0.1764706, 1, 1, 1)
|
|
||||||
|
|
||||||
[sub_resource type="BoxMesh" id="BoxMesh_irf4n"]
|
|
||||||
material = SubResource("StandardMaterial3D_24d3s")
|
|
||||||
size = Vector3(0.1, 0.1, 0.1)
|
|
||||||
|
|
||||||
[node name="CubeSideDispenser2" type="StaticBody3D" unique_id=200950572]
|
|
||||||
script = ExtResource("1_4m60m")
|
|
||||||
item_scene = ExtResource("2_nn8tr")
|
|
||||||
|
|
||||||
[node name="XRToolsSnapZone" type="Area3D" parent="." unique_id=1018021004]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.00070536137, 1.0440714, -0.002165556)
|
|
||||||
collision_layer = 65536
|
|
||||||
collision_mask = 65536
|
|
||||||
script = ExtResource("3_ahn1e")
|
|
||||||
snap_mode = 1
|
|
||||||
metadata/_custom_type_script = "uid://cquqe4f1m1sw6"
|
|
||||||
|
|
||||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="XRToolsSnapZone" unique_id=182042233]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.15291119, 0)
|
|
||||||
shape = SubResource("SphereShape3D_xmbo2")
|
|
||||||
|
|
||||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="." unique_id=1974757539]
|
|
||||||
shape = SubResource("CylinderShape3D_24d3s")
|
|
||||||
|
|
||||||
[node name="SlideOffDome" parent="." unique_id=1427609426 instance=ExtResource("4_nn8tr")]
|
|
||||||
|
|
||||||
[node name="CSGCombiner3D" type="CSGCombiner3D" parent="." unique_id=1172420592]
|
|
||||||
|
|
||||||
[node name="CSGCylinder3D" type="CSGCylinder3D" parent="CSGCombiner3D" unique_id=1073546772]
|
|
||||||
radius = 0.3
|
|
||||||
sides = 32
|
|
||||||
|
|
||||||
[node name="Cubes" type="Node3D" parent="." unique_id=100532970]
|
|
||||||
|
|
||||||
[node name="MeshInstance3D" type="MeshInstance3D" parent="Cubes" unique_id=2040729886]
|
|
||||||
transform = Transform3D(0.9709369, 0, 0.23933554, 0, 1, 0, -0.23933554, 0, 0.9709369, -0.0038359165, 1.0421022, -0.1349423)
|
|
||||||
mesh = SubResource("BoxMesh_irf4n")
|
|
||||||
|
|
||||||
[node name="MeshInstance3D2" type="MeshInstance3D" parent="Cubes" unique_id=2119335322]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.1336323, 1.0421022, 0.049409628)
|
|
||||||
mesh = SubResource("BoxMesh_irf4n")
|
|
||||||
|
|
||||||
[node name="MeshInstance3D3" type="MeshInstance3D" parent="Cubes" unique_id=896999260]
|
|
||||||
transform = Transform3D(0.94914126, 0, -0.31485054, 0, 1, 0, 0.31485054, 0, 0.94914126, 0.021345377, 1.0421022, 0.13508391)
|
|
||||||
mesh = SubResource("BoxMesh_irf4n")
|
|
||||||
|
|
||||||
[node name="MeshInstance3D4" type="MeshInstance3D" parent="Cubes" unique_id=1055210121]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.14830339, 1.0421022, 0.054090023)
|
|
||||||
mesh = SubResource("BoxMesh_irf4n")
|
|
||||||
|
|
||||||
[node name="MeshInstance3D5" type="MeshInstance3D" parent="Cubes" unique_id=1800524097]
|
|
||||||
transform = Transform3D(0.966823, 0, -0.2554472, 0, 1, 0, 0.2554472, 0, 0.966823, 0.12695658, 1.0421022, -0.07926583)
|
|
||||||
mesh = SubResource("BoxMesh_irf4n")
|
|
||||||
|
|
||||||
[node name="MeshInstance3D6" type="MeshInstance3D" parent="Cubes" unique_id=192094054]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.11111963, 1.0421022, -0.094003916)
|
|
||||||
mesh = SubResource("BoxMesh_irf4n")
|
|
||||||
@@ -1,166 +0,0 @@
|
|||||||
[gd_scene format=3 uid="uid://c1nv4w33fedj6"]
|
|
||||||
|
|
||||||
[ext_resource type="Script" uid="uid://b4ldkd3ngs0vp" path="res://main.gd" id="1_72gy5"]
|
|
||||||
[ext_resource type="PackedScene" uid="uid://j5s5wus7tuhb" path="res://XROrigin.tscn" id="2_8wkh3"]
|
|
||||||
[ext_resource type="Material" uid="uid://cmia50cfqxxo4" path="res://Textures/dev_material_3d.tres" id="3_m56cs"]
|
|
||||||
[ext_resource type="PackedScene" uid="uid://j7caslh27nor" path="res://Stations/Hob.tscn" id="4_5kvh0"]
|
|
||||||
[ext_resource type="Sky" uid="uid://c1abtpwhdm2d5" path="res://Textures/sky/NightSkyHDRI009_16K.tres" id="5_l1qm6"]
|
|
||||||
[ext_resource type="PackedScene" uid="uid://c0lknik4noobs" path="res://Items/BurgerBuns.tscn" id="6_bktvt"]
|
|
||||||
[ext_resource type="PackedScene" uid="uid://c6rift56ql3f8" path="res://Stations/BurgerBunsDispenser.tscn" id="7_1nkd0"]
|
|
||||||
[ext_resource type="PackedScene" uid="uid://bp3v1jl8pctro" path="res://Containers/plate.tscn" id="8_l1owj"]
|
|
||||||
[ext_resource type="PackedScene" uid="uid://dpot5qie20vf6" path="res://Items/burger.tscn" id="9_220hi"]
|
|
||||||
[ext_resource type="PackedScene" uid="uid://b3m2ag8g5rj4r" path="res://Items/hamburger.tscn" id="10_qacki"]
|
|
||||||
[ext_resource type="PackedScene" uid="uid://e4i6o5oriecx" path="res://Items/PickupCube.tscn" id="11_npf8s"]
|
|
||||||
[ext_resource type="PackedScene" uid="uid://dvrk268s7gkxh" path="res://Stations/sink.tscn" id="12_8apyq"]
|
|
||||||
[ext_resource type="PackedScene" uid="uid://cnjwtnhwh0i8q" path="res://Stations/dirt_station.tscn" id="13_jnwcx"]
|
|
||||||
[ext_resource type="PackedScene" uid="uid://cfc4ho67u4r5e" path="res://Items/cooked_burger.tscn" id="14_1lg2m"]
|
|
||||||
[ext_resource type="PackedScene" uid="uid://efaec6ymgabo" path="res://Stations/Counter.tscn" id="15_yy81s"]
|
|
||||||
[ext_resource type="PackedScene" uid="uid://clujaf3u776a3" path="res://addons/godot-xr-tools/objects/viewport_2d_in_3d.tscn" id="16_vp"]
|
|
||||||
[ext_resource type="PackedScene" path="res://UI/main_menu_panel.tscn" id="17_panel"]
|
|
||||||
|
|
||||||
[sub_resource type="BoxShape3D" id="BoxShape3D_vlqg6"]
|
|
||||||
size = Vector3(115, 0.1, 15)
|
|
||||||
|
|
||||||
[sub_resource type="BoxMesh" id="BoxMesh_24d3s"]
|
|
||||||
material = ExtResource("3_m56cs")
|
|
||||||
size = Vector3(15, 0.1, 15)
|
|
||||||
|
|
||||||
[sub_resource type="Environment" id="Environment_bvwq1"]
|
|
||||||
background_mode = 2
|
|
||||||
sky = ExtResource("5_l1qm6")
|
|
||||||
reflected_light_source = 2
|
|
||||||
ssr_enabled = true
|
|
||||||
ssao_enabled = true
|
|
||||||
ssil_enabled = true
|
|
||||||
sdfgi_enabled = true
|
|
||||||
|
|
||||||
[node name="Main" type="Node3D" unique_id=1312265607]
|
|
||||||
script = ExtResource("1_72gy5")
|
|
||||||
|
|
||||||
[node name="XROrigin3D" parent="." unique_id=2055526621 instance=ExtResource("2_8wkh3")]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.36171648, 0, 0.81835127)
|
|
||||||
|
|
||||||
[node name="MainMenuPanel3D" parent="." unique_id=1448860532 instance=ExtResource("16_vp")]
|
|
||||||
transform = Transform3D(5, 0, 0, 0, 5, 0, 0, 0, 5, 0.36171648, 2.0238447, -1.9758987)
|
|
||||||
screen_size = Vector2(0.6, 0.4)
|
|
||||||
scene = ExtResource("17_panel")
|
|
||||||
viewport_size = Vector2(600, 400)
|
|
||||||
transparent = 1
|
|
||||||
scene_properties_keys = PackedStringArray("main_menu_panel.gd")
|
|
||||||
|
|
||||||
[node name="DirectionalLight3D" type="DirectionalLight3D" parent="." unique_id=1376644384]
|
|
||||||
transform = Transform3D(-0.8660254, -0.43301278, 0.24999999, 0.3022632, -0.05510214, 0.9516306, -0.39829266, 0.8997021, 0.17860365, 0, 0, 0)
|
|
||||||
|
|
||||||
[node name="Floor" type="StaticBody3D" parent="." unique_id=122279514]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.05, 0)
|
|
||||||
|
|
||||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="Floor" unique_id=958841648]
|
|
||||||
shape = SubResource("BoxShape3D_vlqg6")
|
|
||||||
|
|
||||||
[node name="MeshInstance3D" type="MeshInstance3D" parent="Floor/CollisionShape3D" unique_id=1939997056]
|
|
||||||
mesh = SubResource("BoxMesh_24d3s")
|
|
||||||
|
|
||||||
[node name="Hob" parent="." unique_id=1687971542 instance=ExtResource("4_5kvh0")]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.29336345, 0.5, -1.484)
|
|
||||||
|
|
||||||
[node name="WorldEnvironment" type="WorldEnvironment" parent="." unique_id=1177077250]
|
|
||||||
environment = SubResource("Environment_bvwq1")
|
|
||||||
|
|
||||||
[node name="BurgerBuns" parent="." unique_id=1088240294 instance=ExtResource("6_bktvt")]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -1.5530176, 1.0505146, -1.3074328)
|
|
||||||
|
|
||||||
[node name="BurgerBunsDispenser" parent="." unique_id=1720683779 instance=ExtResource("7_1nkd0")]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -1.568947, -0.018512607, -1.317366)
|
|
||||||
|
|
||||||
[node name="Plate" parent="." unique_id=190487773 instance=ExtResource("8_l1owj")]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -1.5717233, 1.1548845, 1.5373346)
|
|
||||||
|
|
||||||
[node name="burger" parent="." unique_id=1417604760 instance=ExtResource("9_220hi")]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.6888188, 1.0325116, -1.7110313)
|
|
||||||
|
|
||||||
[node name="burger2" parent="." unique_id=1584460510 instance=ExtResource("9_220hi")]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.6931299, 1.1429771, -1.71225)
|
|
||||||
|
|
||||||
[node name="burger3" parent="." unique_id=1884095916 instance=ExtResource("9_220hi")]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.69027674, 1.1099085, -1.7210286)
|
|
||||||
|
|
||||||
[node name="burger4" parent="." unique_id=1844818864 instance=ExtResource("9_220hi")]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.69134104, 1.0672915, -1.7210286)
|
|
||||||
|
|
||||||
[node name="Hamburger" parent="." unique_id=761091445 instance=ExtResource("10_qacki")]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -1.9352558, 1.2334514, 1.2447833)
|
|
||||||
|
|
||||||
[node name="PickableObject" parent="." unique_id=1675596942 instance=ExtResource("11_npf8s")]
|
|
||||||
transform = Transform3D(1, 0, -2.2351742e-08, -2.9802322e-08, 1.0000001, 0, -2.6077032e-08, 1.4901161e-08, 1, 0.6225724, 1.0654817, -1.0473135)
|
|
||||||
|
|
||||||
[node name="PickableObject2" parent="." unique_id=713087634 instance=ExtResource("11_npf8s")]
|
|
||||||
transform = Transform3D(1, 0, -2.2351742e-08, -2.9802322e-08, 1.0000001, -5.293956e-23, -2.6077032e-08, 1.4901161e-08, 1, 0.6359743, 1.0501236, -1.1673055)
|
|
||||||
|
|
||||||
[node name="PickableObject3" parent="." unique_id=879935619 instance=ExtResource("11_npf8s")]
|
|
||||||
transform = Transform3D(1, 0, -2.2351742e-08, -2.9802322e-08, 1.0000001, 0, -2.6077032e-08, 1.4901161e-08, 1, 0.5142721, 1.0654817, -1.0473135)
|
|
||||||
|
|
||||||
[node name="PickableObject4" parent="." unique_id=198541902 instance=ExtResource("11_npf8s")]
|
|
||||||
transform = Transform3D(1, 0, -2.2351742e-08, -2.9802322e-08, 1.0000001, -5.293956e-23, -2.6077032e-08, 1.4901161e-08, 1, 0.5276739, 1.0501236, -1.1673055)
|
|
||||||
|
|
||||||
[node name="Hamburger2" parent="." unique_id=1349934579 instance=ExtResource("10_qacki")]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -1.9857153, 1.1424131, 0.9472374)
|
|
||||||
|
|
||||||
[node name="PickableObject5" parent="." unique_id=1021333509 instance=ExtResource("11_npf8s")]
|
|
||||||
transform = Transform3D(1, 0, -2.2351742e-08, -2.9802322e-08, 1.0000001, 0, -2.6077032e-08, 1.4901161e-08, 1, 0.73287535, 1.0922265, -1.0473135)
|
|
||||||
|
|
||||||
[node name="PickableObject6" parent="." unique_id=1268843669 instance=ExtResource("11_npf8s")]
|
|
||||||
transform = Transform3D(1, 0, -2.2351742e-08, -2.9802322e-08, 1.0000001, -5.293956e-23, -2.6077032e-08, 1.4901161e-08, 1, 0.7462772, 1.0768684, -1.1673055)
|
|
||||||
|
|
||||||
[node name="Sink" parent="." unique_id=2055277359 instance=ExtResource("12_8apyq")]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 1.3147688, 0.5, -1.4940417)
|
|
||||||
|
|
||||||
[node name="DirtStation" parent="." unique_id=160842153 instance=ExtResource("13_jnwcx")]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 2.0864775, 0.5, -1.244947)
|
|
||||||
|
|
||||||
[node name="Plate2" parent="." unique_id=356790445 instance=ExtResource("8_l1owj")]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -1.5730225, 1.1085004, 0.59790254)
|
|
||||||
|
|
||||||
[node name="CookedBurger" parent="." unique_id=1127807542 instance=ExtResource("14_1lg2m")]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.30782473, 1.1446649, -1.0928738)
|
|
||||||
|
|
||||||
[node name="CookedBurger2" parent="." unique_id=160088590 instance=ExtResource("14_1lg2m")]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.30671906, 1.0522771, -1.0928738)
|
|
||||||
|
|
||||||
[node name="CookedBurger3" parent="." unique_id=992183367 instance=ExtResource("14_1lg2m")]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -1.3344773, 1.0492828, -0.7096845)
|
|
||||||
|
|
||||||
[node name="CookedBurger4" parent="." unique_id=1837607086 instance=ExtResource("14_1lg2m")]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.30671906, 1.098119, -1.0928738)
|
|
||||||
|
|
||||||
[node name="BurgerBuns2" parent="." unique_id=1210358958 instance=ExtResource("6_bktvt")]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -1.3596323, 1.0205106, -0.22482127)
|
|
||||||
|
|
||||||
[node name="PickableObject7" parent="." unique_id=641653545 instance=ExtResource("11_npf8s")]
|
|
||||||
transform = Transform3D(1, 0, -2.2351742e-08, -2.9802322e-08, 1.0000001, 0, -2.6077032e-08, 1.4901161e-08, 1, -1.3556751, 1.0887735, 0.28881657)
|
|
||||||
|
|
||||||
[node name="PickableObject8" parent="." unique_id=1733819363 instance=ExtResource("11_npf8s")]
|
|
||||||
transform = Transform3D(1, 0, -2.2351742e-08, -2.9802322e-08, 1.0000001, -5.293956e-23, -2.6077032e-08, 1.4901161e-08, 1, -1.3422732, 1.0734154, 0.16882455)
|
|
||||||
|
|
||||||
[node name="PickableObject9" parent="." unique_id=12419746 instance=ExtResource("11_npf8s")]
|
|
||||||
transform = Transform3D(1, 0, -2.2351742e-08, -2.9802322e-08, 1.0000001, 0, -2.6077032e-08, 1.4901161e-08, 1, -1.4639754, 1.0887735, 0.28881657)
|
|
||||||
|
|
||||||
[node name="PickableObject10" parent="." unique_id=313160217 instance=ExtResource("11_npf8s")]
|
|
||||||
transform = Transform3D(1, 0, -2.2351742e-08, -2.9802322e-08, 1.0000001, -5.293956e-23, -2.6077032e-08, 1.4901161e-08, 1, -1.4505737, 1.0734154, 0.16882455)
|
|
||||||
|
|
||||||
[node name="Counter" parent="." unique_id=1487893288 instance=ExtResource("15_yy81s")]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.7124918, 0.5, -1.4886917)
|
|
||||||
|
|
||||||
[node name="Counter2" parent="." unique_id=368890752 instance=ExtResource("15_yy81s")]
|
|
||||||
transform = Transform3D(-4.371139e-08, 0, 1, 0, 1, 0, -1, 0, -4.371139e-08, -1.7648025, 0.5, -0.4458799)
|
|
||||||
|
|
||||||
[node name="Counter3" parent="." unique_id=1498817646 instance=ExtResource("15_yy81s")]
|
|
||||||
transform = Transform3D(-4.371139e-08, 0, 1, 0, 1, 0, -1, 0, -4.371139e-08, -1.7648025, 0.5, 0.55367994)
|
|
||||||
|
|
||||||
[node name="Counter4" parent="." unique_id=906748771 instance=ExtResource("15_yy81s")]
|
|
||||||
transform = Transform3D(-4.371139e-08, 0, 1, 0, 1, 0, -1, 0, -4.371139e-08, -1.7648025, 0.5, 1.5539298)
|
|
||||||
|
|
||||||
[node name="Hamburger3" parent="." unique_id=369573848 instance=ExtResource("10_qacki")]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -1.7201865, 1.142413, 0.14773655)
|
|
||||||
|
|
||||||
[node name="Plate3" parent="." unique_id=2004250522 instance=ExtResource("8_l1owj")]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -1.5818124, 1.1085004, -0.4634577)
|
|
||||||
@@ -1,76 +0,0 @@
|
|||||||
[gd_scene format=3 uid="uid://c30i6h32w8p47"]
|
|
||||||
|
|
||||||
[ext_resource type="Script" uid="uid://d1cefhe3yyyds" path="res://Scenes/multiplayer_world.gd" id="1_kdan8"]
|
|
||||||
[ext_resource type="PackedScene" uid="uid://j5s5wus7tuhb" path="res://XROrigin.tscn" id="2_g30gi"]
|
|
||||||
[ext_resource type="Material" uid="uid://cmia50cfqxxo4" path="res://Textures/dev_material_3d.tres" id="3_75ecy"]
|
|
||||||
[ext_resource type="Sky" uid="uid://c1abtpwhdm2d5" path="res://Textures/sky/NightSkyHDRI009_16K.tres" id="5_c3xgf"]
|
|
||||||
|
|
||||||
[sub_resource type="BoxShape3D" id="BoxShape3D_vlqg6"]
|
|
||||||
size = Vector3(15, 0.1, 15)
|
|
||||||
|
|
||||||
[sub_resource type="BoxMesh" id="BoxMesh_24d3s"]
|
|
||||||
material = ExtResource("3_75ecy")
|
|
||||||
size = Vector3(15, 0.1, 15)
|
|
||||||
|
|
||||||
[sub_resource type="Environment" id="Environment_bvwq1"]
|
|
||||||
background_mode = 2
|
|
||||||
sky = ExtResource("5_c3xgf")
|
|
||||||
reflected_light_source = 2
|
|
||||||
ssr_enabled = true
|
|
||||||
ssao_enabled = true
|
|
||||||
ssil_enabled = true
|
|
||||||
sdfgi_enabled = true
|
|
||||||
|
|
||||||
[sub_resource type="BoxShape3D" id="BoxShape3D_arao0"]
|
|
||||||
size = Vector3(15, 20, 0.1)
|
|
||||||
|
|
||||||
[node name="Main" type="Node3D" unique_id=1312265607]
|
|
||||||
script = ExtResource("1_kdan8")
|
|
||||||
|
|
||||||
[node name="XROrigin3D" parent="." unique_id=2055526621 groups=["local_xr_origin"] instance=ExtResource("2_g30gi")]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.36171648, 0, 0.81835127)
|
|
||||||
|
|
||||||
[node name="DirectionalLight3D" type="DirectionalLight3D" parent="." unique_id=1376644384]
|
|
||||||
transform = Transform3D(-0.8660254, -0.43301278, 0.24999999, 0.3022632, -0.05510214, 0.9516306, -0.39829266, 0.8997021, 0.17860365, 0, 0, 0)
|
|
||||||
|
|
||||||
[node name="Floor" type="StaticBody3D" parent="." unique_id=122279514]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.05, 0)
|
|
||||||
|
|
||||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="Floor" unique_id=958841648]
|
|
||||||
shape = SubResource("BoxShape3D_vlqg6")
|
|
||||||
|
|
||||||
[node name="MeshInstance3D" type="MeshInstance3D" parent="Floor/CollisionShape3D" unique_id=1939997056]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.00018164515, 0.0006352663, -0.002532661)
|
|
||||||
mesh = SubResource("BoxMesh_24d3s")
|
|
||||||
|
|
||||||
[node name="WorldEnvironment" type="WorldEnvironment" parent="." unique_id=1177077250]
|
|
||||||
environment = SubResource("Environment_bvwq1")
|
|
||||||
|
|
||||||
[node name="WorldContent" type="Node3D" parent="." unique_id=291550153]
|
|
||||||
|
|
||||||
[node name="Players" type="Node3D" parent="." unique_id=1595463693]
|
|
||||||
|
|
||||||
[node name="ItemsSpawner" type="MultiplayerSpawner" parent="." unique_id=627119248]
|
|
||||||
spawn_path = NodePath("../WorldContent")
|
|
||||||
|
|
||||||
[node name="PlayersSpawner" type="MultiplayerSpawner" parent="." unique_id=106645565]
|
|
||||||
_spawnable_scenes = PackedStringArray("res://Player/net_player.tscn")
|
|
||||||
spawn_path = NodePath("../Players")
|
|
||||||
|
|
||||||
[node name="StaticBody3D" type="StaticBody3D" parent="." unique_id=4404969]
|
|
||||||
|
|
||||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="StaticBody3D" unique_id=998476672]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 9.197384, 7.589958)
|
|
||||||
shape = SubResource("BoxShape3D_arao0")
|
|
||||||
|
|
||||||
[node name="CollisionShape3D2" type="CollisionShape3D" parent="StaticBody3D" unique_id=340303902]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 9.197384, -7.509142)
|
|
||||||
shape = SubResource("BoxShape3D_arao0")
|
|
||||||
|
|
||||||
[node name="CollisionShape3D3" type="CollisionShape3D" parent="StaticBody3D" unique_id=1193703037]
|
|
||||||
transform = Transform3D(-4.371139e-08, 0, -1, 0, 1, 0, 1, 0, -4.371139e-08, -7.438612, 9.197384, -0.018813243)
|
|
||||||
shape = SubResource("BoxShape3D_arao0")
|
|
||||||
|
|
||||||
[node name="CollisionShape3D4" type="CollisionShape3D" parent="StaticBody3D" unique_id=1431367494]
|
|
||||||
transform = Transform3D(-4.371139e-08, 0, -1, 0, 1, 0, 1, 0, -4.371139e-08, 7.502467, 9.197384, -0.018813023)
|
|
||||||
shape = SubResource("BoxShape3D_arao0")
|
|
||||||
@@ -1,117 +0,0 @@
|
|||||||
extends Node3D
|
|
||||||
|
|
||||||
## World script for the multiplayer scene. Consumes the host/join request set
|
|
||||||
## by the main menu, spawns the world's stations/items on whichever machine
|
|
||||||
## owns the world (server, or the local player when offline), spawns/despawns
|
|
||||||
## a player avatar per connected peer, and returns to the menu if the session
|
|
||||||
## ends.
|
|
||||||
##
|
|
||||||
## The world's actual content (stations, items) is NOT baked into this scene —
|
|
||||||
## it's spawned at runtime from Net/world_layout.gd via NetworkManager, so a
|
|
||||||
## joining client receives it from the server (MultiplayerSpawner replays
|
|
||||||
## existing spawns to late joiners) instead of relying on its own local copy
|
|
||||||
## matching.
|
|
||||||
|
|
||||||
const PLAYER_SCENE := preload("res://Player/net_player.tscn")
|
|
||||||
|
|
||||||
## Whether to spawn the full WorldLayout on the machine that owns the world.
|
|
||||||
## The real game scene wants this; focused debug scenes (test/) bake their own
|
|
||||||
## handful of stations and items instead and turn it off, so the thing under
|
|
||||||
## test isn't sharing the world with a second copy of the whole kitchen.
|
|
||||||
@export var populate_from_layout: bool = true
|
|
||||||
|
|
||||||
var xr_interface: XRInterface
|
|
||||||
var _populated := false
|
|
||||||
|
|
||||||
|
|
||||||
func _ready() -> void:
|
|
||||||
xr_interface = XRServer.find_interface("OpenXR")
|
|
||||||
if xr_interface and xr_interface.is_initialized():
|
|
||||||
DisplayServer.window_set_vsync_mode(DisplayServer.VSYNC_DISABLED)
|
|
||||||
get_viewport().use_xr = true
|
|
||||||
|
|
||||||
NetworkManager.register_world(self, $PlayersSpawner, $ItemsSpawner)
|
|
||||||
NetworkManager.player_joined.connect(_on_player_joined)
|
|
||||||
NetworkManager.player_left.connect(_on_player_left)
|
|
||||||
NetworkManager.session_started.connect(_on_session_started)
|
|
||||||
NetworkManager.session_ended.connect(_on_session_ended)
|
|
||||||
NetworkManager.connection_failed.connect(_on_connection_failed)
|
|
||||||
|
|
||||||
# world_ready() is what actually calls host()/join() (or the cmdline
|
|
||||||
# equivalent). Populating before this point is wrong for EVERY case, not
|
|
||||||
# just offline: is_online() is still false until host()/join() runs, so
|
|
||||||
# owns_world() would read true for a joining client too, and it would
|
|
||||||
# build its own local copy instead of receiving the server's via the
|
|
||||||
# spawner. host() emits session_started synchronously, which populates
|
|
||||||
# via _on_session_started below; the explicit call after world_ready()
|
|
||||||
# only matters for the case where neither host() nor join() ran (no
|
|
||||||
# pending session, no cmdline args) — running this scene directly offline.
|
|
||||||
NetworkManager.world_ready()
|
|
||||||
_populate_world_if_owner()
|
|
||||||
|
|
||||||
get_tree().create_timer(3.0).timeout.connect(_log_world_state)
|
|
||||||
|
|
||||||
|
|
||||||
# Temporary-ish sanity check: confirms WorldContent actually ended up
|
|
||||||
# populated on this peer (whether by spawning it or by receiving it via
|
|
||||||
# replication), so a silent replication failure shows up in the net log
|
|
||||||
# instead of just an empty-looking world.
|
|
||||||
func _log_world_state() -> void:
|
|
||||||
NetworkManager.log_line("World state: WorldContent=%d children, Players=%d children" % [$WorldContent.get_child_count(), $Players.get_child_count()])
|
|
||||||
|
|
||||||
|
|
||||||
func _exit_tree() -> void:
|
|
||||||
NetworkManager.unregister_world()
|
|
||||||
|
|
||||||
|
|
||||||
func _on_session_started(_is_server: bool) -> void:
|
|
||||||
NetworkManager.gate_existing_stations()
|
|
||||||
_populate_world_if_owner()
|
|
||||||
|
|
||||||
|
|
||||||
## Spawns the world's stations/items exactly once, on the machine that owns
|
|
||||||
## world logic (server or offline). Safe to call multiple times/entry points.
|
|
||||||
func _populate_world_if_owner() -> void:
|
|
||||||
if not NetworkManager.owns_world() or _populated or not populate_from_layout:
|
|
||||||
return
|
|
||||||
_populated = true
|
|
||||||
GameManager.meals_in_play = ["hamburger"]
|
|
||||||
var stations := WorldLayout.get_stations()
|
|
||||||
var items := WorldLayout.get_items()
|
|
||||||
NetworkManager.log_line("Populating world: %d stations, %d items" % [stations.size(), items.size()])
|
|
||||||
for d in stations:
|
|
||||||
NetworkManager.spawn_item(d["scene"], d["xform"], d["name"], d["props"])
|
|
||||||
for d in items:
|
|
||||||
NetworkManager.spawn_item(d["scene"], d["xform"], d["name"], d["props"])
|
|
||||||
NetworkManager.log_line("World populated")
|
|
||||||
|
|
||||||
|
|
||||||
## Only the server (or the single offline machine) materialises player
|
|
||||||
## avatars; MultiplayerSpawner replicates the result to everyone else,
|
|
||||||
## including late joiners.
|
|
||||||
func _on_player_joined(peer_id: int) -> void:
|
|
||||||
if not NetworkManager.owns_world() or $Players.has_node(str(peer_id)):
|
|
||||||
return
|
|
||||||
var p := PLAYER_SCENE.instantiate()
|
|
||||||
p.name = str(peer_id)
|
|
||||||
$Players.add_child(p, true)
|
|
||||||
NetworkManager.log_line("Spawned avatar for peer %d" % peer_id)
|
|
||||||
|
|
||||||
|
|
||||||
func _on_player_left(peer_id: int) -> void:
|
|
||||||
if not NetworkManager.owns_world():
|
|
||||||
return
|
|
||||||
var p := $Players.get_node_or_null(str(peer_id))
|
|
||||||
if p:
|
|
||||||
p.queue_free()
|
|
||||||
NetworkManager.log_line("Despawned avatar for peer %d" % peer_id)
|
|
||||||
|
|
||||||
|
|
||||||
func _on_session_ended() -> void:
|
|
||||||
NetworkManager.log_line("Session ended, returning to main menu")
|
|
||||||
get_tree().change_scene_to_file("res://Scenes/mainMenu.tscn")
|
|
||||||
|
|
||||||
|
|
||||||
func _on_connection_failed() -> void:
|
|
||||||
NetworkManager.log_line("Connection failed, returning to main menu")
|
|
||||||
get_tree().change_scene_to_file("res://Scenes/mainMenu.tscn")
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
uid://d1cefhe3yyyds
|
|
||||||
@@ -1,84 +0,0 @@
|
|||||||
[gd_scene format=3 uid="uid://dbgu4r127ke5v"]
|
|
||||||
|
|
||||||
[ext_resource type="Script" uid="uid://b4ldkd3ngs0vp" path="res://main.gd" id="1_1ymas"]
|
|
||||||
[ext_resource type="Sky" uid="uid://c1abtpwhdm2d5" path="res://Textures/sky/NightSkyHDRI009_16K.tres" id="2_1jq86"]
|
|
||||||
[ext_resource type="PackedScene" uid="uid://j5s5wus7tuhb" path="res://XROrigin.tscn" id="3_bryd6"]
|
|
||||||
[ext_resource type="Material" uid="uid://cmia50cfqxxo4" path="res://Textures/dev_material_3d.tres" id="4_kpgm6"]
|
|
||||||
[ext_resource type="PackedScene" uid="uid://j7caslh27nor" path="res://Stations/Hob.tscn" id="5_gfdi7"]
|
|
||||||
[ext_resource type="PackedScene" uid="uid://dvrk268s7gkxh" path="res://Stations/sink.tscn" id="6_fmmg3"]
|
|
||||||
[ext_resource type="PackedScene" uid="uid://efaec6ymgabo" path="res://Stations/Counter.tscn" id="7_jnxsa"]
|
|
||||||
[ext_resource type="PackedScene" uid="uid://e4i6o5oriecx" path="res://Items/PickupCube.tscn" id="8_xl5nn"]
|
|
||||||
|
|
||||||
[sub_resource type="Environment" id="Environment_bvwq1"]
|
|
||||||
background_mode = 2
|
|
||||||
sky = ExtResource("2_1jq86")
|
|
||||||
ambient_light_source = 3
|
|
||||||
ambient_light_color = Color(1, 1, 1, 1)
|
|
||||||
ambient_light_sky_contribution = 0.9
|
|
||||||
reflected_light_source = 2
|
|
||||||
ssr_enabled = true
|
|
||||||
ssao_enabled = true
|
|
||||||
ssil_enabled = true
|
|
||||||
sdfgi_enabled = true
|
|
||||||
|
|
||||||
[sub_resource type="BoxShape3D" id="BoxShape3D_vlqg6"]
|
|
||||||
size = Vector3(20, 0.1, 20)
|
|
||||||
|
|
||||||
[sub_resource type="BoxMesh" id="BoxMesh_24d3s"]
|
|
||||||
material = ExtResource("4_kpgm6")
|
|
||||||
size = Vector3(20, 0.1, 20)
|
|
||||||
|
|
||||||
[sub_resource type="BoxShape3D" id="BoxShape3D_24d3s"]
|
|
||||||
size = Vector3(20, 10, 0.1)
|
|
||||||
|
|
||||||
[node name="Main" type="Node3D" unique_id=1312265607]
|
|
||||||
script = ExtResource("1_1ymas")
|
|
||||||
|
|
||||||
[node name="WorldEnvironment" type="WorldEnvironment" parent="." unique_id=1177077250]
|
|
||||||
environment = SubResource("Environment_bvwq1")
|
|
||||||
|
|
||||||
[node name="XROrigin3D" parent="." unique_id=2055526621 instance=ExtResource("3_bryd6")]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.9667189, 0)
|
|
||||||
|
|
||||||
[node name="DirectionalLight3D" type="DirectionalLight3D" parent="." unique_id=1376644384]
|
|
||||||
transform = Transform3D(-0.8660254, -0.43301278, 0.24999999, 0.3022632, -0.05510214, 0.9516306, -0.39829266, 0.8997021, 0.17860365, 0, 0, 0)
|
|
||||||
|
|
||||||
[node name="Floor" type="StaticBody3D" parent="." unique_id=122279514]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.05, 0)
|
|
||||||
|
|
||||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="Floor" unique_id=958841648]
|
|
||||||
shape = SubResource("BoxShape3D_vlqg6")
|
|
||||||
|
|
||||||
[node name="MeshInstance3D" type="MeshInstance3D" parent="Floor/CollisionShape3D" unique_id=1939997056]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.00018164515, 0.0006352663, -0.002532661)
|
|
||||||
mesh = SubResource("BoxMesh_24d3s")
|
|
||||||
|
|
||||||
[node name="InvisibleWalls" type="StaticBody3D" parent="." unique_id=315740174]
|
|
||||||
|
|
||||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="InvisibleWalls" unique_id=33059670]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 4.688614, 8.838269)
|
|
||||||
shape = SubResource("BoxShape3D_24d3s")
|
|
||||||
|
|
||||||
[node name="CollisionShape3D2" type="CollisionShape3D" parent="InvisibleWalls" unique_id=2018792171]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 4.688614, -10.243342)
|
|
||||||
shape = SubResource("BoxShape3D_24d3s")
|
|
||||||
|
|
||||||
[node name="CollisionShape3D3" type="CollisionShape3D" parent="InvisibleWalls" unique_id=757662929]
|
|
||||||
transform = Transform3D(-4.371139e-08, 0, -1, 0, 1, 0, 1, 0, -4.371139e-08, -9.807113, 4.688614, -0.018813243)
|
|
||||||
shape = SubResource("BoxShape3D_24d3s")
|
|
||||||
|
|
||||||
[node name="CollisionShape3D4" type="CollisionShape3D" parent="InvisibleWalls" unique_id=1468386997]
|
|
||||||
transform = Transform3D(-4.371139e-08, 0, -1, 0, 1, 0, 1, 0, -4.371139e-08, 9.934778, 4.297072, -0.018813023)
|
|
||||||
shape = SubResource("BoxShape3D_24d3s")
|
|
||||||
|
|
||||||
[node name="Hob" parent="." unique_id=1687971542 instance=ExtResource("5_gfdi7")]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.35077858, 0.50655985, -1.2833805)
|
|
||||||
|
|
||||||
[node name="Sink" parent="." unique_id=2055277359 instance=ExtResource("6_fmmg3")]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.24685252, 0.51461196, -1.2828919)
|
|
||||||
|
|
||||||
[node name="Counter" parent="." unique_id=1487893288 instance=ExtResource("7_jnxsa")]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.94890714, 0.5115015, -1.3041471)
|
|
||||||
|
|
||||||
[node name="PickableObject" parent="." unique_id=1675596942 instance=ExtResource("8_xl5nn")]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.87560004, 1.5534955, -1.2869046)
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
extends Node
|
|
||||||
|
|
||||||
signal game_over
|
|
||||||
signal restart_game
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
uid://fuux6cxfjwdc
|
|
||||||
Binary file not shown.
@@ -1,24 +0,0 @@
|
|||||||
[remap]
|
|
||||||
|
|
||||||
importer="wav"
|
|
||||||
type="AudioStreamWAV"
|
|
||||||
uid="uid://mmasxwqyqmib"
|
|
||||||
path="res://.godot/imported/220175__gameaudio__pop-click.wav-1330523e09eacb15d341a14b80e4481e.sample"
|
|
||||||
|
|
||||||
[deps]
|
|
||||||
|
|
||||||
source_file="res://Sounds/220175__gameaudio__pop-click.wav"
|
|
||||||
dest_files=["res://.godot/imported/220175__gameaudio__pop-click.wav-1330523e09eacb15d341a14b80e4481e.sample"]
|
|
||||||
|
|
||||||
[params]
|
|
||||||
|
|
||||||
force/8_bit=false
|
|
||||||
force/mono=false
|
|
||||||
force/max_rate=false
|
|
||||||
force/max_rate_hz=44100
|
|
||||||
edit/trim=false
|
|
||||||
edit/normalize=false
|
|
||||||
edit/loop_mode=0
|
|
||||||
edit/loop_begin=0
|
|
||||||
edit/loop_end=-1
|
|
||||||
compress/mode=2
|
|
||||||
Binary file not shown.
@@ -1,24 +0,0 @@
|
|||||||
[remap]
|
|
||||||
|
|
||||||
importer="wav"
|
|
||||||
type="AudioStreamWAV"
|
|
||||||
uid="uid://ecva70pect61"
|
|
||||||
path="res://.godot/imported/220178__gameaudio__click.wav-ca46bf33c1c48e1e526f04c43ca7d450.sample"
|
|
||||||
|
|
||||||
[deps]
|
|
||||||
|
|
||||||
source_file="res://Sounds/220178__gameaudio__click.wav"
|
|
||||||
dest_files=["res://.godot/imported/220178__gameaudio__click.wav-ca46bf33c1c48e1e526f04c43ca7d450.sample"]
|
|
||||||
|
|
||||||
[params]
|
|
||||||
|
|
||||||
force/8_bit=false
|
|
||||||
force/mono=false
|
|
||||||
force/max_rate=false
|
|
||||||
force/max_rate_hz=44100
|
|
||||||
edit/trim=false
|
|
||||||
edit/normalize=false
|
|
||||||
edit/loop_mode=0
|
|
||||||
edit/loop_begin=0
|
|
||||||
edit/loop_end=-1
|
|
||||||
compress/mode=2
|
|
||||||
Binary file not shown.
@@ -1,24 +0,0 @@
|
|||||||
[remap]
|
|
||||||
|
|
||||||
importer="wav"
|
|
||||||
type="AudioStreamWAV"
|
|
||||||
uid="uid://b3wxawyrvuc6s"
|
|
||||||
path="res://.godot/imported/220179__gameaudio__click-metal-ting.wav-b01c457287fe42298a36c3de7c536c68.sample"
|
|
||||||
|
|
||||||
[deps]
|
|
||||||
|
|
||||||
source_file="res://Sounds/220179__gameaudio__click-metal-ting.wav"
|
|
||||||
dest_files=["res://.godot/imported/220179__gameaudio__click-metal-ting.wav-b01c457287fe42298a36c3de7c536c68.sample"]
|
|
||||||
|
|
||||||
[params]
|
|
||||||
|
|
||||||
force/8_bit=false
|
|
||||||
force/mono=false
|
|
||||||
force/max_rate=false
|
|
||||||
force/max_rate_hz=44100
|
|
||||||
edit/trim=false
|
|
||||||
edit/normalize=false
|
|
||||||
edit/loop_mode=0
|
|
||||||
edit/loop_begin=0
|
|
||||||
edit/loop_end=-1
|
|
||||||
compress/mode=2
|
|
||||||
Binary file not shown.
@@ -1,24 +0,0 @@
|
|||||||
[remap]
|
|
||||||
|
|
||||||
importer="wav"
|
|
||||||
type="AudioStreamWAV"
|
|
||||||
uid="uid://b7sr2sb1ks5en"
|
|
||||||
path="res://.godot/imported/220180__gameaudio__click-pop.wav-9e467150046193d705dd830885c89cd1.sample"
|
|
||||||
|
|
||||||
[deps]
|
|
||||||
|
|
||||||
source_file="res://Sounds/220180__gameaudio__click-pop.wav"
|
|
||||||
dest_files=["res://.godot/imported/220180__gameaudio__click-pop.wav-9e467150046193d705dd830885c89cd1.sample"]
|
|
||||||
|
|
||||||
[params]
|
|
||||||
|
|
||||||
force/8_bit=false
|
|
||||||
force/mono=false
|
|
||||||
force/max_rate=false
|
|
||||||
force/max_rate_hz=44100
|
|
||||||
edit/trim=false
|
|
||||||
edit/normalize=false
|
|
||||||
edit/loop_mode=0
|
|
||||||
edit/loop_begin=0
|
|
||||||
edit/loop_end=-1
|
|
||||||
compress/mode=2
|
|
||||||
Binary file not shown.
@@ -1,24 +0,0 @@
|
|||||||
[remap]
|
|
||||||
|
|
||||||
importer="wav"
|
|
||||||
type="AudioStreamWAV"
|
|
||||||
uid="uid://1ccsqbju32ey"
|
|
||||||
path="res://.godot/imported/220187__gameaudio__loosedeny-casual-1.wav-cb0e560d42c6026ded2d2e240e614433.sample"
|
|
||||||
|
|
||||||
[deps]
|
|
||||||
|
|
||||||
source_file="res://Sounds/220187__gameaudio__loosedeny-casual-1.wav"
|
|
||||||
dest_files=["res://.godot/imported/220187__gameaudio__loosedeny-casual-1.wav-cb0e560d42c6026ded2d2e240e614433.sample"]
|
|
||||||
|
|
||||||
[params]
|
|
||||||
|
|
||||||
force/8_bit=false
|
|
||||||
force/mono=false
|
|
||||||
force/max_rate=false
|
|
||||||
force/max_rate_hz=44100
|
|
||||||
edit/trim=false
|
|
||||||
edit/normalize=false
|
|
||||||
edit/loop_mode=0
|
|
||||||
edit/loop_begin=0
|
|
||||||
edit/loop_end=-1
|
|
||||||
compress/mode=2
|
|
||||||
Binary file not shown.
@@ -1,24 +0,0 @@
|
|||||||
[remap]
|
|
||||||
|
|
||||||
importer="wav"
|
|
||||||
type="AudioStreamWAV"
|
|
||||||
uid="uid://bdnsgt7xt3261"
|
|
||||||
path="res://.godot/imported/220194__gameaudio__click-heavy.wav-aca40ed286d93eb365d527a162fd3129.sample"
|
|
||||||
|
|
||||||
[deps]
|
|
||||||
|
|
||||||
source_file="res://Sounds/220194__gameaudio__click-heavy.wav"
|
|
||||||
dest_files=["res://.godot/imported/220194__gameaudio__click-heavy.wav-aca40ed286d93eb365d527a162fd3129.sample"]
|
|
||||||
|
|
||||||
[params]
|
|
||||||
|
|
||||||
force/8_bit=false
|
|
||||||
force/mono=false
|
|
||||||
force/max_rate=false
|
|
||||||
force/max_rate_hz=44100
|
|
||||||
edit/trim=false
|
|
||||||
edit/normalize=false
|
|
||||||
edit/loop_mode=0
|
|
||||||
edit/loop_begin=0
|
|
||||||
edit/loop_end=-1
|
|
||||||
compress/mode=2
|
|
||||||
Binary file not shown.
@@ -1,24 +0,0 @@
|
|||||||
[remap]
|
|
||||||
|
|
||||||
importer="wav"
|
|
||||||
type="AudioStreamWAV"
|
|
||||||
uid="uid://daiv8ubwdbidf"
|
|
||||||
path="res://.godot/imported/220195__gameaudio__click-wooden-1.wav-9368ef861eabf2cf1d5bd0db33c616c8.sample"
|
|
||||||
|
|
||||||
[deps]
|
|
||||||
|
|
||||||
source_file="res://Sounds/220195__gameaudio__click-wooden-1.wav"
|
|
||||||
dest_files=["res://.godot/imported/220195__gameaudio__click-wooden-1.wav-9368ef861eabf2cf1d5bd0db33c616c8.sample"]
|
|
||||||
|
|
||||||
[params]
|
|
||||||
|
|
||||||
force/8_bit=false
|
|
||||||
force/mono=false
|
|
||||||
force/max_rate=false
|
|
||||||
force/max_rate_hz=44100
|
|
||||||
edit/trim=false
|
|
||||||
edit/normalize=false
|
|
||||||
edit/loop_mode=0
|
|
||||||
edit/loop_begin=0
|
|
||||||
edit/loop_end=-1
|
|
||||||
compress/mode=2
|
|
||||||
Binary file not shown.
@@ -1,24 +0,0 @@
|
|||||||
[remap]
|
|
||||||
|
|
||||||
importer="wav"
|
|
||||||
type="AudioStreamWAV"
|
|
||||||
uid="uid://qed775b4j1gg"
|
|
||||||
path="res://.godot/imported/220196__gameaudio__click-wooden-2.wav-45bb63efefaf817b60155beec9343d74.sample"
|
|
||||||
|
|
||||||
[deps]
|
|
||||||
|
|
||||||
source_file="res://Sounds/220196__gameaudio__click-wooden-2.wav"
|
|
||||||
dest_files=["res://.godot/imported/220196__gameaudio__click-wooden-2.wav-45bb63efefaf817b60155beec9343d74.sample"]
|
|
||||||
|
|
||||||
[params]
|
|
||||||
|
|
||||||
force/8_bit=false
|
|
||||||
force/mono=false
|
|
||||||
force/max_rate=false
|
|
||||||
force/max_rate_hz=44100
|
|
||||||
edit/trim=false
|
|
||||||
edit/normalize=false
|
|
||||||
edit/loop_mode=0
|
|
||||||
edit/loop_begin=0
|
|
||||||
edit/loop_end=-1
|
|
||||||
compress/mode=2
|
|
||||||
Binary file not shown.
@@ -1,24 +0,0 @@
|
|||||||
[remap]
|
|
||||||
|
|
||||||
importer="wav"
|
|
||||||
type="AudioStreamWAV"
|
|
||||||
uid="uid://bqtk1adk8umbx"
|
|
||||||
path="res://.godot/imported/220197__gameaudio__click-basic.wav-9f173e2b7206278e95710ab077d62c32.sample"
|
|
||||||
|
|
||||||
[deps]
|
|
||||||
|
|
||||||
source_file="res://Sounds/220197__gameaudio__click-basic.wav"
|
|
||||||
dest_files=["res://.godot/imported/220197__gameaudio__click-basic.wav-9f173e2b7206278e95710ab077d62c32.sample"]
|
|
||||||
|
|
||||||
[params]
|
|
||||||
|
|
||||||
force/8_bit=false
|
|
||||||
force/mono=false
|
|
||||||
force/max_rate=false
|
|
||||||
force/max_rate_hz=44100
|
|
||||||
edit/trim=false
|
|
||||||
edit/normalize=false
|
|
||||||
edit/loop_mode=0
|
|
||||||
edit/loop_begin=0
|
|
||||||
edit/loop_end=-1
|
|
||||||
compress/mode=2
|
|
||||||
Binary file not shown.
@@ -1,24 +0,0 @@
|
|||||||
[remap]
|
|
||||||
|
|
||||||
importer="wav"
|
|
||||||
type="AudioStreamWAV"
|
|
||||||
uid="uid://ysgfx76jkx2q"
|
|
||||||
path="res://.godot/imported/220198__gameaudio__click-with-two-parts.wav-089977567529b37b0fd9cd019eb7b3c2.sample"
|
|
||||||
|
|
||||||
[deps]
|
|
||||||
|
|
||||||
source_file="res://Sounds/220198__gameaudio__click-with-two-parts.wav"
|
|
||||||
dest_files=["res://.godot/imported/220198__gameaudio__click-with-two-parts.wav-089977567529b37b0fd9cd019eb7b3c2.sample"]
|
|
||||||
|
|
||||||
[params]
|
|
||||||
|
|
||||||
force/8_bit=false
|
|
||||||
force/mono=false
|
|
||||||
force/max_rate=false
|
|
||||||
force/max_rate_hz=44100
|
|
||||||
edit/trim=false
|
|
||||||
edit/normalize=false
|
|
||||||
edit/loop_mode=0
|
|
||||||
edit/loop_begin=0
|
|
||||||
edit/loop_end=-1
|
|
||||||
compress/mode=2
|
|
||||||
Binary file not shown.
@@ -1,24 +0,0 @@
|
|||||||
[remap]
|
|
||||||
|
|
||||||
importer="wav"
|
|
||||||
type="AudioStreamWAV"
|
|
||||||
uid="uid://dtyh22ccebiv5"
|
|
||||||
path="res://.godot/imported/220199__gameaudio__click-higher.wav-d1c1550d99a0cc873012c4010877005b.sample"
|
|
||||||
|
|
||||||
[deps]
|
|
||||||
|
|
||||||
source_file="res://Sounds/220199__gameaudio__click-higher.wav"
|
|
||||||
dest_files=["res://.godot/imported/220199__gameaudio__click-higher.wav-d1c1550d99a0cc873012c4010877005b.sample"]
|
|
||||||
|
|
||||||
[params]
|
|
||||||
|
|
||||||
force/8_bit=false
|
|
||||||
force/mono=false
|
|
||||||
force/max_rate=false
|
|
||||||
force/max_rate_hz=44100
|
|
||||||
edit/trim=false
|
|
||||||
edit/normalize=false
|
|
||||||
edit/loop_mode=0
|
|
||||||
edit/loop_begin=0
|
|
||||||
edit/loop_end=-1
|
|
||||||
compress/mode=2
|
|
||||||
Binary file not shown.
@@ -1,24 +0,0 @@
|
|||||||
[remap]
|
|
||||||
|
|
||||||
importer="wav"
|
|
||||||
type="AudioStreamWAV"
|
|
||||||
uid="uid://cywjbbeintjew"
|
|
||||||
path="res://.godot/imported/220208__gameaudio__click-pop-two-part.wav-04cb5eb3e0b3459771dbab42bbd24be9.sample"
|
|
||||||
|
|
||||||
[deps]
|
|
||||||
|
|
||||||
source_file="res://Sounds/220208__gameaudio__click-pop-two-part.wav"
|
|
||||||
dest_files=["res://.godot/imported/220208__gameaudio__click-pop-two-part.wav-04cb5eb3e0b3459771dbab42bbd24be9.sample"]
|
|
||||||
|
|
||||||
[params]
|
|
||||||
|
|
||||||
force/8_bit=false
|
|
||||||
force/mono=false
|
|
||||||
force/max_rate=false
|
|
||||||
force/max_rate_hz=44100
|
|
||||||
edit/trim=false
|
|
||||||
edit/normalize=false
|
|
||||||
edit/loop_mode=0
|
|
||||||
edit/loop_begin=0
|
|
||||||
edit/loop_end=-1
|
|
||||||
compress/mode=2
|
|
||||||
Binary file not shown.
@@ -1,24 +0,0 @@
|
|||||||
[remap]
|
|
||||||
|
|
||||||
importer="wav"
|
|
||||||
type="AudioStreamWAV"
|
|
||||||
uid="uid://claw3d2wnyr6a"
|
|
||||||
path="res://.godot/imported/220212__gameaudio__ping-bing.wav-2a1049829e71a0034c7e8d18745663f1.sample"
|
|
||||||
|
|
||||||
[deps]
|
|
||||||
|
|
||||||
source_file="res://Sounds/220212__gameaudio__ping-bing.wav"
|
|
||||||
dest_files=["res://.godot/imported/220212__gameaudio__ping-bing.wav-2a1049829e71a0034c7e8d18745663f1.sample"]
|
|
||||||
|
|
||||||
[params]
|
|
||||||
|
|
||||||
force/8_bit=false
|
|
||||||
force/mono=false
|
|
||||||
force/max_rate=false
|
|
||||||
force/max_rate_hz=44100
|
|
||||||
edit/trim=false
|
|
||||||
edit/normalize=false
|
|
||||||
edit/loop_mode=0
|
|
||||||
edit/loop_begin=0
|
|
||||||
edit/loop_end=-1
|
|
||||||
compress/mode=2
|
|
||||||
@@ -3,13 +3,11 @@
|
|||||||
[ext_resource type="Script" uid="uid://0y6wnjcsum6" path="res://Stations/item_dispenser.gd" id="1_myl3s"]
|
[ext_resource type="Script" uid="uid://0y6wnjcsum6" path="res://Stations/item_dispenser.gd" id="1_myl3s"]
|
||||||
[ext_resource type="Script" uid="uid://cquqe4f1m1sw6" path="res://addons/godot-xr-tools/objects/snap_zone.gd" id="1_p30r1"]
|
[ext_resource type="Script" uid="uid://cquqe4f1m1sw6" path="res://addons/godot-xr-tools/objects/snap_zone.gd" id="1_p30r1"]
|
||||||
[ext_resource type="PackedScene" uid="uid://c0lknik4noobs" path="res://Items/BurgerBuns.tscn" id="2_1q74o"]
|
[ext_resource type="PackedScene" uid="uid://c0lknik4noobs" path="res://Items/BurgerBuns.tscn" id="2_1q74o"]
|
||||||
[ext_resource type="PackedScene" uid="uid://mpapt5mkbuao" path="res://Prefabs/slide_off_dome.tscn" id="4_rf1b2"]
|
|
||||||
|
|
||||||
[sub_resource type="SphereShape3D" id="SphereShape3D_xmbo2"]
|
[sub_resource type="SphereShape3D" id="SphereShape3D_xmbo2"]
|
||||||
radius = 0.3
|
radius = 0.3
|
||||||
|
|
||||||
[sub_resource type="CylinderShape3D" id="CylinderShape3D_24d3s"]
|
[sub_resource type="CylinderShape3D" id="CylinderShape3D_24d3s"]
|
||||||
radius = 0.3
|
|
||||||
|
|
||||||
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_vlqg6"]
|
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_vlqg6"]
|
||||||
albedo_color = Color(0.6784191, 0.54546416, 0.016760282, 1)
|
albedo_color = Color(0.6784191, 0.54546416, 0.016760282, 1)
|
||||||
@@ -24,6 +22,7 @@ collision_layer = 65536
|
|||||||
collision_mask = 65536
|
collision_mask = 65536
|
||||||
script = ExtResource("1_p30r1")
|
script = ExtResource("1_p30r1")
|
||||||
snap_mode = 1
|
snap_mode = 1
|
||||||
|
initial_object = NodePath("../../BurgerBuns")
|
||||||
metadata/_custom_type_script = "uid://cquqe4f1m1sw6"
|
metadata/_custom_type_script = "uid://cquqe4f1m1sw6"
|
||||||
|
|
||||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="XRToolsSnapZone" unique_id=1104626493]
|
[node name="CollisionShape3D" type="CollisionShape3D" parent="XRToolsSnapZone" unique_id=1104626493]
|
||||||
@@ -32,16 +31,14 @@ shape = SubResource("SphereShape3D_xmbo2")
|
|||||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="." unique_id=1470079357]
|
[node name="CollisionShape3D" type="CollisionShape3D" parent="." unique_id=1470079357]
|
||||||
shape = SubResource("CylinderShape3D_24d3s")
|
shape = SubResource("CylinderShape3D_24d3s")
|
||||||
|
|
||||||
[node name="SlideOffDome" parent="." unique_id=1427609426 instance=ExtResource("4_rf1b2")]
|
|
||||||
|
|
||||||
[node name="CSGCombiner3D" type="CSGCombiner3D" parent="." unique_id=1746426494]
|
[node name="CSGCombiner3D" type="CSGCombiner3D" parent="." unique_id=1746426494]
|
||||||
|
|
||||||
[node name="CSGCylinder3D" type="CSGCylinder3D" parent="CSGCombiner3D" unique_id=858311379]
|
[node name="CSGCylinder3D" type="CSGCylinder3D" parent="CSGCombiner3D" unique_id=858311379]
|
||||||
radius = 0.3
|
radius = 0.4
|
||||||
sides = 32
|
sides = 32
|
||||||
|
|
||||||
[node name="CSGCombiner3DBuns" type="CSGCombiner3D" parent="CSGCombiner3D" unique_id=1459017790]
|
[node name="CSGCombiner3DBuns" type="CSGCombiner3D" parent="CSGCombiner3D" unique_id=1459017790]
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.16038476, 1.0341886, -0.09012994)
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.108142376, 1.0341886, -0.19146484)
|
||||||
autosmooth = true
|
autosmooth = true
|
||||||
smoothing_angle = 138.9
|
smoothing_angle = 138.9
|
||||||
|
|
||||||
@@ -122,7 +119,7 @@ cone = true
|
|||||||
material = SubResource("StandardMaterial3D_vlqg6")
|
material = SubResource("StandardMaterial3D_vlqg6")
|
||||||
|
|
||||||
[node name="CSGCombiner3DBuns4" type="CSGCombiner3D" parent="CSGCombiner3D" unique_id=2055085730]
|
[node name="CSGCombiner3DBuns4" type="CSGCombiner3D" parent="CSGCombiner3D" unique_id=2055085730]
|
||||||
transform = Transform3D(0.95670986, 0, 0.29104328, 0, 1, 0, -0.29104328, 0, 0.95670986, -0.08665481, 1.0341886, -0.10344604)
|
transform = Transform3D(0.95670986, 0, 0.29104328, 0, 1, 0, -0.29104328, 0, 0.95670986, -0.14758292, 1.0341886, -0.1304872)
|
||||||
autosmooth = true
|
autosmooth = true
|
||||||
smoothing_angle = 138.9
|
smoothing_angle = 138.9
|
||||||
|
|
||||||
@@ -149,7 +146,7 @@ cone = true
|
|||||||
material = SubResource("StandardMaterial3D_vlqg6")
|
material = SubResource("StandardMaterial3D_vlqg6")
|
||||||
|
|
||||||
[node name="CSGCombiner3DBuns5" type="CSGCombiner3D" parent="CSGCombiner3D" unique_id=546748728]
|
[node name="CSGCombiner3DBuns5" type="CSGCombiner3D" parent="CSGCombiner3D" unique_id=546748728]
|
||||||
transform = Transform3D(0.20608562, 0, -0.978534, 0, 1, 0, 0.978534, 0, 0.20608562, -0.047733016, 1.0341886, 0.19433105)
|
transform = Transform3D(0.20608562, 0, -0.978534, 0, 1, 0, 0.978534, 0, 0.20608562, -0.082762055, 1.0341886, 0.2722176)
|
||||||
autosmooth = true
|
autosmooth = true
|
||||||
smoothing_angle = 138.9
|
smoothing_angle = 138.9
|
||||||
|
|
||||||
|
|||||||
+16
-70
@@ -1,88 +1,34 @@
|
|||||||
[gd_scene format=3 uid="uid://efaec6ymgabo"]
|
[gd_scene format=3 uid="uid://efaec6ymgabo"]
|
||||||
|
|
||||||
[ext_resource type="Script" uid="uid://cquqe4f1m1sw6" path="res://addons/godot-xr-tools/objects/snap_zone.gd" id="1_dlkho"]
|
[ext_resource type="Script" uid="uid://cquqe4f1m1sw6" path="res://addons/godot-xr-tools/objects/snap_zone.gd" id="1_dlkho"]
|
||||||
[ext_resource type="AudioStream" uid="uid://claw3d2wnyr6a" path="res://Sounds/220212__gameaudio__ping-bing.wav" id="2_0aadn"]
|
|
||||||
|
|
||||||
[sub_resource type="BoxShape3D" id="BoxShape3D_24d3s"]
|
[sub_resource type="BoxShape3D" id="BoxShape3D_24d3s"]
|
||||||
size = Vector3(0.6, 1, 0.6)
|
|
||||||
|
|
||||||
[sub_resource type="BoxShape3D" id="BoxShape3D_1ntq7"]
|
[sub_resource type="BoxMesh" id="BoxMesh_i5j2u"]
|
||||||
size = Vector3(0.6, 0.12802735, 0.6)
|
|
||||||
|
|
||||||
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_24d3s"]
|
[sub_resource type="SphereShape3D" id="SphereShape3D_dlkho"]
|
||||||
albedo_color = Color(0.49, 0.3854667, 0.29400003, 1)
|
radius = 0.3
|
||||||
|
|
||||||
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_pt8vn"]
|
|
||||||
albedo_color = Color(0.66595805, 0.53976387, 0.4331022, 1)
|
|
||||||
|
|
||||||
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_vlqg6"]
|
|
||||||
albedo_color = Color(1.1759251, 0.741115, 0.5692133, 1)
|
|
||||||
|
|
||||||
[node name="Counter" type="StaticBody3D" unique_id=1487893288 groups=["station"]]
|
[node name="Counter" type="StaticBody3D" unique_id=1487893288 groups=["station"]]
|
||||||
|
|
||||||
[node name="CollisionShape3DCuttingBoard" type="CollisionShape3D" parent="." unique_id=706340473]
|
[node name="CollisionShape3D" type="CollisionShape3D" parent="." unique_id=692568688]
|
||||||
shape = SubResource("BoxShape3D_24d3s")
|
shape = SubResource("BoxShape3D_24d3s")
|
||||||
|
|
||||||
|
[node name="MeshInstance3D" type="MeshInstance3D" parent="CollisionShape3D" unique_id=127773521]
|
||||||
|
mesh = SubResource("BoxMesh_i5j2u")
|
||||||
|
|
||||||
|
[node name="Label3D" type="Label3D" parent="CollisionShape3D" unique_id=149978729]
|
||||||
|
transform = Transform3D(0.9999992, 0, 0, 0, 0.99999946, 0, 0, 0, 0.9999992, 0.002797456, 0.6309581, -0.2812457)
|
||||||
|
text = "Counter"
|
||||||
|
|
||||||
[node name="XRToolsSnapZone" type="Area3D" parent="." unique_id=1647380272 groups=["station"]]
|
[node name="XRToolsSnapZone" type="Area3D" parent="." unique_id=1647380272 groups=["station"]]
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.5608841, 0)
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.5270121, 0)
|
||||||
collision_layer = 65536
|
collision_layer = 65536
|
||||||
collision_mask = 65540
|
collision_mask = 65536
|
||||||
script = ExtResource("1_dlkho")
|
script = ExtResource("1_dlkho")
|
||||||
stash_sound = ExtResource("2_0aadn")
|
snap_mode = 0
|
||||||
snap_mode = 1
|
|
||||||
metadata/_custom_type_script = "uid://cquqe4f1m1sw6"
|
metadata/_custom_type_script = "uid://cquqe4f1m1sw6"
|
||||||
|
|
||||||
[node name="CollisionShape3D2" type="CollisionShape3D" parent="XRToolsSnapZone" unique_id=969340130]
|
[node name="CollisionShape3D2" type="CollisionShape3D" parent="XRToolsSnapZone" unique_id=969340130]
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.002, 0)
|
transform = Transform3D(0.5, 0, 0, 0, 0.5, 0, 0, 0, 0.5, 0, -0.000975132, 0)
|
||||||
shape = SubResource("BoxShape3D_1ntq7")
|
shape = SubResource("SphereShape3D_dlkho")
|
||||||
|
|
||||||
[node name="CSGCombiner3D" type="CSGCombiner3D" parent="." unique_id=451757283]
|
|
||||||
use_collision = true
|
|
||||||
|
|
||||||
[node name="CSGBox3D" type="CSGBox3D" parent="CSGCombiner3D" unique_id=305755330]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.046, -0.025)
|
|
||||||
size = Vector3(0.6, 0.908, 0.55)
|
|
||||||
material = SubResource("StandardMaterial3D_24d3s")
|
|
||||||
|
|
||||||
[node name="CSGBox3D7" type="CSGBox3D" parent="CSGCombiner3D" unique_id=1086568272]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.39999902, 0.22965088)
|
|
||||||
operation = 2
|
|
||||||
size = Vector3(0.6, 0.22992969, 0.14069825)
|
|
||||||
material = SubResource("StandardMaterial3D_24d3s")
|
|
||||||
|
|
||||||
[node name="CSGBox3D2" type="CSGBox3D" parent="CSGCombiner3D" unique_id=43663195]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.5, 0)
|
|
||||||
size = Vector3(0.6, 0.202, 0.6)
|
|
||||||
|
|
||||||
[node name="CSGBox3D3" type="CSGBox3D" parent="CSGCombiner3D" unique_id=1210567516]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.5617909, 0.060281754)
|
|
||||||
operation = 2
|
|
||||||
size = Vector3(0.6, 0.12051563, 0.6402156)
|
|
||||||
|
|
||||||
[node name="CSGBox3D4" type="CSGBox3D" parent="CSGCombiner3D" unique_id=1533996708]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.15, 0.08, 0.26034504)
|
|
||||||
size = Vector3(0.25, 0.6, 0.024)
|
|
||||||
material = SubResource("StandardMaterial3D_pt8vn")
|
|
||||||
|
|
||||||
[node name="CSGBox3D5" type="CSGBox3D" parent="CSGCombiner3D" unique_id=1983709234]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.15, 0.08, 0.26034504)
|
|
||||||
size = Vector3(0.25, 0.6, 0.024)
|
|
||||||
material = SubResource("StandardMaterial3D_pt8vn")
|
|
||||||
|
|
||||||
[node name="CSGSphere3D" type="CSGSphere3D" parent="CSGCombiner3D" unique_id=1785057925]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.057649717, 0.12459713, 0.29140875)
|
|
||||||
radius = 0.025492515
|
|
||||||
|
|
||||||
[node name="CSGSphere3D2" type="CSGSphere3D" parent="CSGCombiner3D" unique_id=1224446005]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.060837455, 0.12459713, 0.29140875)
|
|
||||||
radius = 0.025492515
|
|
||||||
|
|
||||||
[node name="CSGBox3D6" type="CSGBox3D" parent="CSGCombiner3D" unique_id=187377667]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.514, 0)
|
|
||||||
size = Vector3(0.48251343, 0.037231445, 0.42160034)
|
|
||||||
material = SubResource("StandardMaterial3D_vlqg6")
|
|
||||||
|
|
||||||
[node name="CSGBox3D6" type="CSGBox3D" parent="CSGCombiner3D/CSGBox3D6" unique_id=1146824846]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.1899699, 0.01924485, -0.0039587095)
|
|
||||||
operation = 2
|
|
||||||
size = Vector3(0.037109375, 0.092285156, 0.26757813)
|
|
||||||
|
|||||||
+26
-209
@@ -1,233 +1,50 @@
|
|||||||
[gd_scene format=3 uid="uid://j7caslh27nor"]
|
[gd_scene format=3 uid="uid://j7caslh27nor"]
|
||||||
|
|
||||||
[ext_resource type="Script" uid="uid://bsn8vhv5adxdo" path="res://Stations/hob.gd" id="1_7jc4g"]
|
[ext_resource type="Script" uid="uid://bsn8vhv5adxdo" path="res://Stations/hob.gd" id="1_7jc4g"]
|
||||||
|
[ext_resource type="Texture2D" uid="uid://b7n8d4krwbcvl" path="res://Textures/5.png" id="2_0sasq"]
|
||||||
[ext_resource type="Script" uid="uid://cquqe4f1m1sw6" path="res://addons/godot-xr-tools/objects/snap_zone.gd" id="2_er1dp"]
|
[ext_resource type="Script" uid="uid://cquqe4f1m1sw6" path="res://addons/godot-xr-tools/objects/snap_zone.gd" id="2_er1dp"]
|
||||||
[ext_resource type="PackedScene" uid="uid://bxbocxdaayvwx" path="res://UI/progress_bar.tscn" id="3_7uuqv"]
|
|
||||||
|
|
||||||
[sub_resource type="BoxShape3D" id="BoxShape3D_kdxnr"]
|
[sub_resource type="BoxShape3D" id="BoxShape3D_24d3s"]
|
||||||
size = Vector3(0.6, 1, 0.6)
|
|
||||||
|
|
||||||
[sub_resource type="BoxShape3D" id="BoxShape3D_7uuqv"]
|
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_m5xe2"]
|
||||||
size = Vector3(0.6, 0.12802735, 0.6)
|
albedo_texture = ExtResource("2_0sasq")
|
||||||
|
uv1_triplanar = true
|
||||||
|
|
||||||
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_di04w"]
|
[sub_resource type="BoxMesh" id="BoxMesh_i5j2u"]
|
||||||
albedo_color = Color(0, 0, 0, 1)
|
material = SubResource("StandardMaterial3D_m5xe2")
|
||||||
|
|
||||||
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_gkb3v"]
|
[sub_resource type="SphereShape3D" id="SphereShape3D_vlqg6"]
|
||||||
|
radius = 0.3
|
||||||
|
|
||||||
[sub_resource type="SceneReplicationConfig" id="SceneReplicationConfig_np_hob"]
|
[sub_resource type="SceneReplicationConfig" id="Repl_hob"]
|
||||||
properties/0/path = NodePath(".:time_cooked")
|
properties/0/path = NodePath(".:progress")
|
||||||
properties/0/spawn = true
|
properties/0/spawn = true
|
||||||
properties/0/replication_mode = 1
|
properties/0/replication_mode = 1
|
||||||
properties/1/path = NodePath(".:cooking_result_time")
|
|
||||||
properties/1/spawn = true
|
|
||||||
properties/1/replication_mode = 1
|
|
||||||
|
|
||||||
[sub_resource type="Animation" id="Animation_7uuqv"]
|
|
||||||
length = 0.001
|
|
||||||
tracks/0/type = "bezier"
|
|
||||||
tracks/0/imported = false
|
|
||||||
tracks/0/enabled = true
|
|
||||||
tracks/0/path = NodePath("CSGCombiner3D/CSGTorus3D:material:albedo_color:r")
|
|
||||||
tracks/0/interp = 1
|
|
||||||
tracks/0/loop_wrap = true
|
|
||||||
tracks/0/keys = {
|
|
||||||
"handle_modes": PackedInt32Array(0),
|
|
||||||
"points": PackedFloat32Array(0, -0.25, 0, 0.25, 0),
|
|
||||||
"times": PackedFloat32Array(0)
|
|
||||||
}
|
|
||||||
tracks/1/type = "bezier"
|
|
||||||
tracks/1/imported = false
|
|
||||||
tracks/1/enabled = true
|
|
||||||
tracks/1/path = NodePath("CSGCombiner3D/CSGTorus3D:material:albedo_color:g")
|
|
||||||
tracks/1/interp = 1
|
|
||||||
tracks/1/loop_wrap = true
|
|
||||||
tracks/1/keys = {
|
|
||||||
"handle_modes": PackedInt32Array(0),
|
|
||||||
"points": PackedFloat32Array(0, -0.25, 0, 0.25, 0),
|
|
||||||
"times": PackedFloat32Array(0)
|
|
||||||
}
|
|
||||||
tracks/2/type = "bezier"
|
|
||||||
tracks/2/imported = false
|
|
||||||
tracks/2/enabled = true
|
|
||||||
tracks/2/path = NodePath("CSGCombiner3D/CSGTorus3D:material:albedo_color:b")
|
|
||||||
tracks/2/interp = 1
|
|
||||||
tracks/2/loop_wrap = true
|
|
||||||
tracks/2/keys = {
|
|
||||||
"handle_modes": PackedInt32Array(0),
|
|
||||||
"points": PackedFloat32Array(0, -0.25, 0, 0.25, 0),
|
|
||||||
"times": PackedFloat32Array(0)
|
|
||||||
}
|
|
||||||
tracks/3/type = "bezier"
|
|
||||||
tracks/3/imported = false
|
|
||||||
tracks/3/enabled = true
|
|
||||||
tracks/3/path = NodePath("CSGCombiner3D/CSGTorus3D:material:albedo_color:a")
|
|
||||||
tracks/3/interp = 1
|
|
||||||
tracks/3/loop_wrap = true
|
|
||||||
tracks/3/keys = {
|
|
||||||
"handle_modes": PackedInt32Array(0),
|
|
||||||
"points": PackedFloat32Array(1, -0.25, 0, 0.25, 0),
|
|
||||||
"times": PackedFloat32Array(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
[sub_resource type="Animation" id="Animation_6oyg1"]
|
|
||||||
resource_name = "hob"
|
|
||||||
loop_mode = 1
|
|
||||||
tracks/0/type = "bezier"
|
|
||||||
tracks/0/imported = false
|
|
||||||
tracks/0/enabled = true
|
|
||||||
tracks/0/path = NodePath("CSGCombiner3D/CSGTorus3D:material:albedo_color:r")
|
|
||||||
tracks/0/interp = 1
|
|
||||||
tracks/0/loop_wrap = true
|
|
||||||
tracks/0/keys = {
|
|
||||||
"handle_modes": PackedInt32Array(0, 2, 2),
|
|
||||||
"points": PackedFloat32Array(0.5, -0.25, 0, 0.25, 0, 0.8, -0.083333336, 0, 0, 0, 0.5, -0.083333336, 0, 0, 0),
|
|
||||||
"times": PackedFloat32Array(0, 0.5, 1)
|
|
||||||
}
|
|
||||||
tracks/1/type = "bezier"
|
|
||||||
tracks/1/imported = false
|
|
||||||
tracks/1/enabled = true
|
|
||||||
tracks/1/path = NodePath("CSGCombiner3D/CSGTorus3D:material:albedo_color:g")
|
|
||||||
tracks/1/interp = 1
|
|
||||||
tracks/1/loop_wrap = true
|
|
||||||
tracks/1/keys = {
|
|
||||||
"handle_modes": PackedInt32Array(0, 2, 2),
|
|
||||||
"points": PackedFloat32Array(0, -0.25, 0, 0.25, 0, 0, -0.083333336, 0, 0, 0, 0, -0.083333336, 0, 0, 0),
|
|
||||||
"times": PackedFloat32Array(0, 0.5, 1)
|
|
||||||
}
|
|
||||||
tracks/2/type = "bezier"
|
|
||||||
tracks/2/imported = false
|
|
||||||
tracks/2/enabled = true
|
|
||||||
tracks/2/path = NodePath("CSGCombiner3D/CSGTorus3D:material:albedo_color:b")
|
|
||||||
tracks/2/interp = 1
|
|
||||||
tracks/2/loop_wrap = true
|
|
||||||
tracks/2/keys = {
|
|
||||||
"handle_modes": PackedInt32Array(0, 2, 2),
|
|
||||||
"points": PackedFloat32Array(0, -0.25, 0, 0.25, 0, 0, -0.083333336, 0, 0, 0, 0, -0.083333336, 0, 0, 0),
|
|
||||||
"times": PackedFloat32Array(0, 0.5, 1)
|
|
||||||
}
|
|
||||||
tracks/3/type = "bezier"
|
|
||||||
tracks/3/imported = false
|
|
||||||
tracks/3/enabled = true
|
|
||||||
tracks/3/path = NodePath("CSGCombiner3D/CSGTorus3D:material:albedo_color:a")
|
|
||||||
tracks/3/interp = 1
|
|
||||||
tracks/3/loop_wrap = true
|
|
||||||
tracks/3/keys = {
|
|
||||||
"handle_modes": PackedInt32Array(0, 2, 2),
|
|
||||||
"points": PackedFloat32Array(1, -0.25, 0, 0.25, 0, 1, -0.083333336, 0, 0, 0, 1, -0.083333336, 0, 0, 0),
|
|
||||||
"times": PackedFloat32Array(0, 0.5, 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
[sub_resource type="AnimationLibrary" id="AnimationLibrary_ac5f3"]
|
|
||||||
_data = {
|
|
||||||
&"RESET": SubResource("Animation_7uuqv"),
|
|
||||||
&"hob": SubResource("Animation_6oyg1")
|
|
||||||
}
|
|
||||||
|
|
||||||
[node name="Hob" type="StaticBody3D" unique_id=1687971542 groups=["station"]]
|
[node name="Hob" type="StaticBody3D" unique_id=1687971542 groups=["station"]]
|
||||||
script = ExtResource("1_7jc4g")
|
script = ExtResource("1_7jc4g")
|
||||||
|
|
||||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="." unique_id=1283846023]
|
[node name="CollisionShape3D" type="CollisionShape3D" parent="." unique_id=1283846023]
|
||||||
shape = SubResource("BoxShape3D_kdxnr")
|
shape = SubResource("BoxShape3D_24d3s")
|
||||||
|
|
||||||
[node name="XRToolsSnapZone" type="Area3D" parent="." unique_id=538157739 groups=["station"]]
|
[node name="MeshInstance3D" type="MeshInstance3D" parent="CollisionShape3D" unique_id=1454284058]
|
||||||
|
mesh = SubResource("BoxMesh_i5j2u")
|
||||||
|
|
||||||
|
[node name="Label3D" type="Label3D" parent="CollisionShape3D" unique_id=757148654]
|
||||||
|
transform = Transform3D(0.9999992, 0, 0, 0, 0.99999946, 0, 0, 0, 0.9999992, 0.002797456, 0.6309581, -0.2812457)
|
||||||
|
text = "Hob"
|
||||||
|
|
||||||
|
[node name="XRToolsSnapZone" type="Area3D" parent="." unique_id=538157739]
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.5270121, 0)
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.5270121, 0)
|
||||||
collision_layer = 65536
|
collision_layer = 65536
|
||||||
collision_mask = 65540
|
collision_mask = 65536
|
||||||
script = ExtResource("2_er1dp")
|
script = ExtResource("2_er1dp")
|
||||||
snap_mode = 1
|
snap_mode = 0
|
||||||
metadata/_custom_type_script = "uid://cquqe4f1m1sw6"
|
metadata/_custom_type_script = "uid://cquqe4f1m1sw6"
|
||||||
|
|
||||||
[node name="CollisionShape3D2" type="CollisionShape3D" parent="XRToolsSnapZone" unique_id=370920392]
|
[node name="CollisionShape3D2" type="CollisionShape3D" parent="XRToolsSnapZone" unique_id=370920392]
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.000975132, 0)
|
transform = Transform3D(0.5, 0, 0, 0, 0.5, 0, 0, 0, 0.5, 0, -0.000975132, 0)
|
||||||
shape = SubResource("BoxShape3D_7uuqv")
|
shape = SubResource("SphereShape3D_vlqg6")
|
||||||
|
|
||||||
[node name="CSGCombiner3D" type="CSGCombiner3D" parent="." unique_id=70901698]
|
[node name="ProgressSync" type="MultiplayerSynchronizer" parent="."]
|
||||||
|
replication_config = SubResource("Repl_hob")
|
||||||
[node name="CSGBox3D" type="CSGBox3D" parent="CSGCombiner3D" unique_id=1111505172]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -0.00894776)
|
|
||||||
size = Vector3(0.6, 1, 0.5821045)
|
|
||||||
|
|
||||||
[node name="CSGCylinder3D" type="CSGCylinder3D" parent="CSGCombiner3D/CSGBox3D" unique_id=1338463939]
|
|
||||||
transform = Transform3D(0.8943019, 0, 0, 0, 0.8943019, 0, 0, 0, 0.8943019, 0, 0.5103538, -7.827557e-05)
|
|
||||||
operation = 2
|
|
||||||
radius = 0.25976563
|
|
||||||
height = 0.08898926
|
|
||||||
sides = 32
|
|
||||||
|
|
||||||
[node name="CSGTorus3D3" type="CSGTorus3D" parent="CSGCombiner3D" unique_id=666891341]
|
|
||||||
transform = Transform3D(0.8943019, 0, 0, 0, 0.8943019, 0, 0, 0, 0.8943019, 0, 0.5003869, -7.827557e-05)
|
|
||||||
inner_radius = 0.09153879
|
|
||||||
outer_radius = 0.120084204
|
|
||||||
sides = 32
|
|
||||||
material = SubResource("StandardMaterial3D_di04w")
|
|
||||||
|
|
||||||
[node name="CSGTorus3D" type="CSGTorus3D" parent="CSGCombiner3D" unique_id=1901978664]
|
|
||||||
transform = Transform3D(0.8943019, 0, 0, 0, 0.8943019, 0, 0, 0, 0.8943019, 0, 0.5003869, -7.827557e-05)
|
|
||||||
inner_radius = 0.20426142
|
|
||||||
outer_radius = 0.2321898
|
|
||||||
sides = 32
|
|
||||||
material = SubResource("StandardMaterial3D_di04w")
|
|
||||||
|
|
||||||
[node name="CSGTorus3D2" type="CSGTorus3D" parent="CSGCombiner3D" unique_id=24541894]
|
|
||||||
transform = Transform3D(0.8943019, 0, 0, 0, 0.8943019, 0, 0, 0, 0.8943019, 0, 0.5003869, -7.827557e-05)
|
|
||||||
inner_radius = 0.15036294
|
|
||||||
outer_radius = 0.17592031
|
|
||||||
sides = 32
|
|
||||||
material = SubResource("StandardMaterial3D_di04w")
|
|
||||||
|
|
||||||
[node name="CSGCylinder3D" type="CSGCylinder3D" parent="CSGCombiner3D" unique_id=1107239311]
|
|
||||||
transform = Transform3D(0.8943019, 0, 0, 0, 0.8943019, 0, 0, 0, 0.8943019, 0, 0.4498226, -7.827557e-05)
|
|
||||||
radius = 0.071777344
|
|
||||||
height = 0.09637451
|
|
||||||
sides = 32
|
|
||||||
|
|
||||||
[node name="CSGCylinder3D2" type="CSGCylinder3D" parent="CSGCombiner3D" unique_id=435540815]
|
|
||||||
transform = Transform3D(0.8943019, 0, 0, 0, -3.9091177e-08, 0.8943019, 0, -0.8943019, -3.9091177e-08, 0, 0.48668858, -0.0020651226)
|
|
||||||
radius = 0.008
|
|
||||||
height = 0.44487303
|
|
||||||
|
|
||||||
[node name="CSGCylinder3D3" type="CSGCylinder3D" parent="CSGCombiner3D" unique_id=878171801]
|
|
||||||
transform = Transform3D(-3.9091177e-08, -0.8943019, -3.9091177e-08, 0, -3.9091177e-08, 0.8943019, -0.8943019, 3.9091177e-08, 1.7087296e-15, 0, 0.48668858, -0.0020651226)
|
|
||||||
radius = 0.008
|
|
||||||
height = 0.44487303
|
|
||||||
|
|
||||||
[node name="CSGCylinder3D4" type="CSGCylinder3D" parent="CSGCombiner3D" unique_id=1619646436]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, -4.371139e-08, 1, 0, -1, -4.371139e-08, -0.20412213, 0.42728558, 0.26171687)
|
|
||||||
radius = 0.044433594
|
|
||||||
height = 0.10932617
|
|
||||||
material = SubResource("StandardMaterial3D_gkb3v")
|
|
||||||
|
|
||||||
[node name="CSGCylinder3D5" type="CSGCylinder3D" parent="CSGCombiner3D" unique_id=548846612]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, -4.371139e-08, 1, 0, -1, -4.371139e-08, 0.12531614, 0.42728558, 0.26171687)
|
|
||||||
radius = 0.044433594
|
|
||||||
height = 0.10932617
|
|
||||||
material = SubResource("StandardMaterial3D_gkb3v")
|
|
||||||
|
|
||||||
[node name="CSGCylinder3D6" type="CSGCylinder3D" parent="CSGCombiner3D" unique_id=1208989647]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, -4.371139e-08, 1, 0, -1, -4.371139e-08, 0.22979808, 0.42728558, 0.26171687)
|
|
||||||
radius = 0.044433594
|
|
||||||
height = 0.10932617
|
|
||||||
material = SubResource("StandardMaterial3D_gkb3v")
|
|
||||||
|
|
||||||
[node name="CSGBox3D2" type="CSGBox3D" parent="CSGCombiner3D" unique_id=465340362]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.039733887, -0.07685089, 0.29250562)
|
|
||||||
operation = 2
|
|
||||||
size = Vector3(1.0999756, 0.8462982, 0.072387695)
|
|
||||||
|
|
||||||
[node name="CSGBox3D3" type="CSGBox3D" parent="CSGCombiner3D" unique_id=1813079759]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.003479004, -0.08253479, 0.2656765)
|
|
||||||
size = Vector3(0.55, 0.835, 0.072)
|
|
||||||
|
|
||||||
[node name="CSGBox3D4" type="CSGBox3D" parent="CSGCombiner3D" unique_id=1978186019]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.003479004, -0.45215607, 0.24655426)
|
|
||||||
size = Vector3(0.55, 0.096, 0.14)
|
|
||||||
|
|
||||||
[node name="Sync" type="MultiplayerSynchronizer" parent="." unique_id=768992259]
|
|
||||||
replication_config = SubResource("SceneReplicationConfig_np_hob")
|
|
||||||
|
|
||||||
[node name="ProgressBar3D" parent="." unique_id=654673176 instance=ExtResource("3_7uuqv")]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.74736404, -0.09216304)
|
|
||||||
|
|
||||||
[node name="AnimationPlayer" type="AnimationPlayer" parent="." unique_id=1525460719]
|
|
||||||
libraries/ = SubResource("AnimationLibrary_ac5f3")
|
|
||||||
|
|||||||
@@ -1,19 +0,0 @@
|
|||||||
extends StaticBody3D
|
|
||||||
|
|
||||||
@onready var snap_zone: XRToolsSnapZone = $XRToolsSnapZone
|
|
||||||
|
|
||||||
# Called when the node enters the scene tree for the first time.
|
|
||||||
func _ready() -> void:
|
|
||||||
snap_zone.has_picked_up.connect(_makeDirty)
|
|
||||||
|
|
||||||
func _makeDirty(item) -> void:
|
|
||||||
if not NetworkManager.owns_world():
|
|
||||||
return
|
|
||||||
var plate: PlateController = item.get_node_or_null("PlateController") as PlateController
|
|
||||||
if not plate:
|
|
||||||
print("Dirt Station: held object is not a Plate")
|
|
||||||
return
|
|
||||||
if not plate.is_dirty:
|
|
||||||
plate.is_dirty = true
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
uid://q7tpwmrbmu1m
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
[gd_scene format=3 uid="uid://cnjwtnhwh0i8q"]
|
|
||||||
|
|
||||||
[ext_resource type="Script" uid="uid://q7tpwmrbmu1m" path="res://Stations/dirt_station.gd" id="1_hc1d4"]
|
|
||||||
[ext_resource type="Script" uid="uid://cquqe4f1m1sw6" path="res://addons/godot-xr-tools/objects/snap_zone.gd" id="2_v0ytd"]
|
|
||||||
|
|
||||||
[sub_resource type="BoxShape3D" id="BoxShape3D_24d3s"]
|
|
||||||
size = Vector3(0.5, 1, 0.5)
|
|
||||||
|
|
||||||
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_qn1ku"]
|
|
||||||
albedo_color = Color(0.45262197, 0.26770625, 0.2601587, 1)
|
|
||||||
|
|
||||||
[sub_resource type="BoxMesh" id="BoxMesh_ay2w6"]
|
|
||||||
material = SubResource("StandardMaterial3D_qn1ku")
|
|
||||||
size = Vector3(0.5, 1, 0.5)
|
|
||||||
|
|
||||||
[sub_resource type="BoxShape3D" id="BoxShape3D_mep2a"]
|
|
||||||
size = Vector3(0.81640625, 0.5635376, 0.79351807)
|
|
||||||
|
|
||||||
[node name="DirtStation" type="StaticBody3D" unique_id=160842153 groups=["station"]]
|
|
||||||
script = ExtResource("1_hc1d4")
|
|
||||||
|
|
||||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="." unique_id=1400366312]
|
|
||||||
shape = SubResource("BoxShape3D_24d3s")
|
|
||||||
|
|
||||||
[node name="MeshInstance3D" type="MeshInstance3D" parent="CollisionShape3D" unique_id=55726639]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.008318901, 0, -0.022509098)
|
|
||||||
mesh = SubResource("BoxMesh_ay2w6")
|
|
||||||
|
|
||||||
[node name="Label3D" type="Label3D" parent="CollisionShape3D" unique_id=1251766743]
|
|
||||||
transform = Transform3D(0.9999992, 0, 0, 0, 0.99999946, 0, 0, 0, 0.9999992, 0.002797456, 0.6309581, -0.2812457)
|
|
||||||
text = "Dirt"
|
|
||||||
|
|
||||||
[node name="XRToolsSnapZone" type="Area3D" parent="." unique_id=333161027 groups=["station"]]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.5270121, 0)
|
|
||||||
collision_layer = 65536
|
|
||||||
collision_mask = 65540
|
|
||||||
script = ExtResource("2_v0ytd")
|
|
||||||
snap_mode = 1
|
|
||||||
metadata/_custom_type_script = "uid://cquqe4f1m1sw6"
|
|
||||||
|
|
||||||
[node name="CollisionShape3D2" type="CollisionShape3D" parent="XRToolsSnapZone" unique_id=1398712192]
|
|
||||||
transform = Transform3D(0.5, 0, 0, 0, 0.5, 0, 0, 0, 0.5, 0.008666992, -0.11009073, -0.009353638)
|
|
||||||
shape = SubResource("BoxShape3D_mep2a")
|
|
||||||
+43
-75
@@ -1,94 +1,62 @@
|
|||||||
extends StaticBody3D
|
extends StaticBody3D
|
||||||
|
|
||||||
const RECIPE_MANAGER = preload("res://RecipeManager.gd")
|
## Cooking station. The cook timer and item conversion run only on the machine
|
||||||
|
## that owns world logic (server or offline host); `progress` is replicated to
|
||||||
|
## clients for UI via a MultiplayerSynchronizer. This is the reference
|
||||||
|
## implementation of the reusable "station work-progress" pattern: a server-owned
|
||||||
|
## progress value advanced by an input source (here, a timer), which converts the
|
||||||
|
## held item once it reaches the threshold and spawns the result over the network.
|
||||||
|
|
||||||
@export var cook_speed = 1
|
@export var cook_speed := 1.0
|
||||||
@onready var snap_zone: XRToolsSnapZone = $XRToolsSnapZone
|
@onready var snap_zone: XRToolsSnapZone = $XRToolsSnapZone
|
||||||
@onready var progress_bar: ProgressBar3D = $ProgressBar3D
|
|
||||||
|
|
||||||
var time_cooked = 0
|
var item = null
|
||||||
var cooking_result: String
|
var progress: float = 0.0
|
||||||
var cooking_result_time = 0
|
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
if not progress_bar or progress_bar is not ProgressBar3D:
|
if snap_zone.initial_object:
|
||||||
push_error("Hob missing reference to progressbar, or wrong type:", progress_bar)
|
item = snap_zone.initial_object
|
||||||
snap_zone.has_picked_up.connect(_on_object_picked_up)
|
|
||||||
snap_zone.has_dropped.connect(_on_object_dropped)
|
|
||||||
_refresh_progress_bar()
|
|
||||||
|
|
||||||
|
|
||||||
func _refresh_progress_bar() -> void:
|
func convert_item(cookable: CookableItem) -> void:
|
||||||
var progress := 0.0
|
|
||||||
if cooking_result and cooking_result_time > 0:
|
|
||||||
progress = clampf(float(time_cooked) / cooking_result_time, 0.0, 1.0)
|
|
||||||
|
|
||||||
#print("time_cooked: %s / cooking_result_time: %s = progress: %s" % [time_cooked, cooking_result_time, progress])
|
|
||||||
progress_bar.set_progress(progress)
|
|
||||||
progress_bar.set_bar_visible(not cooking_result.is_empty())
|
|
||||||
progress_bar.override_fill_color(Color.RED if cooking_result == "charcoal" else Color.GREEN)
|
|
||||||
|
|
||||||
func _on_object_picked_up(_item) -> void:
|
|
||||||
print("Hob: object picked up: ", _item)
|
|
||||||
|
|
||||||
# Find the CookableItem in held object
|
|
||||||
var _food_item = _item.get_node_or_null("FoodItem") as FoodItem
|
|
||||||
if not _food_item:
|
|
||||||
print("Hob: held object is not a FoodItem")
|
|
||||||
return
|
|
||||||
var result = RECIPE_MANAGER.get_cooking_result(_food_item.id)
|
|
||||||
if not result:
|
|
||||||
print("Hob: held a FoodItem that is not cookable, id: %s result: %s" % [_food_item.id, result])
|
|
||||||
return
|
|
||||||
|
|
||||||
cooking_result = result
|
|
||||||
cooking_result_time = RECIPE_MANAGER.get_cooking_time(_food_item.id)
|
|
||||||
print("Hob: set cooking_result ", cooking_result)
|
|
||||||
_refresh_progress_bar()
|
|
||||||
$AnimationPlayer.play("hob")
|
|
||||||
|
|
||||||
|
|
||||||
func _on_object_dropped() -> void:
|
|
||||||
print("Hob: object drop ")
|
|
||||||
$AnimationPlayer.play("RESET")
|
|
||||||
time_cooked = 0
|
|
||||||
cooking_result = ""
|
|
||||||
cooking_result_time = 0
|
|
||||||
_refresh_progress_bar()
|
|
||||||
|
|
||||||
|
|
||||||
func convert_held_to_item(_item: String) -> void:
|
|
||||||
if not NetworkManager.owns_world():
|
|
||||||
return
|
|
||||||
print("Hob converting ", _item)
|
|
||||||
$AnimationPlayer.play("RESET")
|
|
||||||
|
|
||||||
|
|
||||||
var old_pickable = snap_zone.picked_up_object
|
var old_pickable = snap_zone.picked_up_object
|
||||||
if not old_pickable:
|
if not old_pickable:
|
||||||
push_warning("Hob finished cooking _item, but snap zone is missing its reference")
|
push_warning("Hob finished cooking item, but snap zone is missing its reference")
|
||||||
return
|
return
|
||||||
|
|
||||||
# Spawn the new item through the server so it replicates to every peer
|
var original_transform: Transform3D = old_pickable.global_transform
|
||||||
# (including late joiners), in the old item's position.
|
|
||||||
var original_transform = old_pickable.global_transform
|
|
||||||
var new_scene_instance = NetworkManager.spawn_item(RECIPE_MANAGER.get_item_scene(_item).resource_path, original_transform)
|
|
||||||
|
|
||||||
# Drop and free the old item and pick up the new one
|
# Spawn the result over the network (server) or locally (offline).
|
||||||
print("Hob freeing old_pickable ", old_pickable)
|
var result := NetworkManager.spawn_item(cookable.turns_into.resource_path, original_transform)
|
||||||
|
|
||||||
|
# Remove the cooked item (despawn replicates for spawner-managed items).
|
||||||
snap_zone.drop_object()
|
snap_zone.drop_object()
|
||||||
NetworkManager.despawn_item(old_pickable)
|
old_pickable.queue_free()
|
||||||
snap_zone.pick_up_object(new_scene_instance)
|
|
||||||
|
# Snap the result into the now-empty zone.
|
||||||
|
if result:
|
||||||
|
snap_zone.pick_up_object(result)
|
||||||
|
|
||||||
|
|
||||||
# If cooking something, progress cooking, when done, convert item
|
|
||||||
func _process(delta: float) -> void:
|
func _process(delta: float) -> void:
|
||||||
if cooking_result:
|
# Only the world owner runs cooking logic; clients receive `progress` + the
|
||||||
#print("Hob cooking_result: ", cooking_result)
|
# converted item via replication.
|
||||||
time_cooked += cook_speed * delta
|
if not NetworkManager.owns_world():
|
||||||
_refresh_progress_bar()
|
return
|
||||||
if time_cooked >= cooking_result_time:
|
|
||||||
time_cooked = 0
|
|
||||||
convert_held_to_item(cooking_result)
|
|
||||||
|
|
||||||
|
# Find the CookableItem in the held object.
|
||||||
|
var cookable = null
|
||||||
|
if snap_zone.picked_up_object:
|
||||||
|
var matches = snap_zone.picked_up_object.get_children().filter(func(c): return c is CookableItem)
|
||||||
|
if matches.size() > 0:
|
||||||
|
cookable = matches[0]
|
||||||
|
|
||||||
|
# Advance progress and convert once cooked.
|
||||||
|
if cookable:
|
||||||
|
progress += cook_speed * delta
|
||||||
|
if progress >= cookable.cooking_time:
|
||||||
|
progress = 0.0
|
||||||
|
convert_item(cookable)
|
||||||
|
else:
|
||||||
|
progress = 0.0
|
||||||
|
|||||||
@@ -13,8 +13,10 @@ func _ready() -> void:
|
|||||||
|
|
||||||
# Called every frame. 'delta' is the elapsed time since the previous frame.
|
# Called every frame. 'delta' is the elapsed time since the previous frame.
|
||||||
func _process(delta: float) -> void:
|
func _process(delta: float) -> void:
|
||||||
|
# Only the world owner dispenses, so every client doesn't spawn its own copy.
|
||||||
if not NetworkManager.owns_world():
|
if not NetworkManager.owns_world():
|
||||||
return
|
return
|
||||||
if not snap_zone.picked_up_object:
|
if not snap_zone.picked_up_object:
|
||||||
var new_item = NetworkManager.spawn_item(item_scene.resource_path, snap_zone.global_transform)
|
var new_item := NetworkManager.spawn_item(item_scene.resource_path, snap_zone.global_transform)
|
||||||
snap_zone.pick_up_object(new_item)
|
if new_item:
|
||||||
|
snap_zone.pick_up_object(new_item)
|
||||||
|
|||||||
@@ -1,107 +0,0 @@
|
|||||||
[gd_scene format=3 uid="uid://ck5tuftqmyiue"]
|
|
||||||
|
|
||||||
[ext_resource type="Script" uid="uid://0y6wnjcsum6" path="res://Stations/item_dispenser.gd" id="1_jm0ik"]
|
|
||||||
[ext_resource type="PackedScene" uid="uid://bp3v1jl8pctro" path="res://Containers/plate.tscn" id="2_tfo2i"]
|
|
||||||
[ext_resource type="Script" uid="uid://cquqe4f1m1sw6" path="res://addons/godot-xr-tools/objects/snap_zone.gd" id="3_lr065"]
|
|
||||||
[ext_resource type="PackedScene" uid="uid://mpapt5mkbuao" path="res://Prefabs/slide_off_dome.tscn" id="4_tfo2i"]
|
|
||||||
|
|
||||||
[sub_resource type="SphereShape3D" id="SphereShape3D_xmbo2"]
|
|
||||||
radius = 0.3
|
|
||||||
|
|
||||||
[sub_resource type="CylinderShape3D" id="CylinderShape3D_24d3s"]
|
|
||||||
radius = 0.3
|
|
||||||
|
|
||||||
[node name="PlateDispenser" type="StaticBody3D" unique_id=710538846]
|
|
||||||
script = ExtResource("1_jm0ik")
|
|
||||||
item_scene = ExtResource("2_tfo2i")
|
|
||||||
|
|
||||||
[node name="XRToolsSnapZone" type="Area3D" parent="." unique_id=238176038]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.00070536137, 1.1603245, -0.002165556)
|
|
||||||
collision_layer = 65536
|
|
||||||
collision_mask = 65536
|
|
||||||
script = ExtResource("3_lr065")
|
|
||||||
snap_mode = 1
|
|
||||||
metadata/_custom_type_script = "uid://cquqe4f1m1sw6"
|
|
||||||
|
|
||||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="XRToolsSnapZone" unique_id=1942470044]
|
|
||||||
shape = SubResource("SphereShape3D_xmbo2")
|
|
||||||
|
|
||||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="." unique_id=831688237]
|
|
||||||
shape = SubResource("CylinderShape3D_24d3s")
|
|
||||||
|
|
||||||
[node name="SlideOffDome" parent="." unique_id=1427609426 instance=ExtResource("4_tfo2i")]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.061363697, 0)
|
|
||||||
|
|
||||||
[node name="CSGCombiner3D" type="CSGCombiner3D" parent="." unique_id=696108271]
|
|
||||||
|
|
||||||
[node name="CSGCylinder3D" type="CSGCylinder3D" parent="CSGCombiner3D" unique_id=1339763385]
|
|
||||||
radius = 0.3
|
|
||||||
sides = 32
|
|
||||||
|
|
||||||
[node name="Plates" type="Node3D" parent="." unique_id=1364909922]
|
|
||||||
|
|
||||||
[node name="CSGCombiner3D" type="CSGCombiner3D" parent="Plates" unique_id=2128650644]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.0289642, 0)
|
|
||||||
autosmooth = true
|
|
||||||
smoothing_angle = 103.9
|
|
||||||
|
|
||||||
[node name="CSGCylinder3D" type="CSGCylinder3D" parent="Plates/CSGCombiner3D" unique_id=472067854]
|
|
||||||
radius = 0.2
|
|
||||||
height = 0.03
|
|
||||||
sides = 16
|
|
||||||
|
|
||||||
[node name="CSGCylinder3D" type="CSGCylinder3D" parent="Plates/CSGCombiner3D/CSGCylinder3D" unique_id=7092994]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.010312311, 0)
|
|
||||||
operation = 2
|
|
||||||
radius = 0.15
|
|
||||||
height = 0.03
|
|
||||||
sides = 16
|
|
||||||
|
|
||||||
[node name="CSGCylinder3D2" type="CSGCylinder3D" parent="Plates/CSGCombiner3D" unique_id=23957958]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.027119078, 0)
|
|
||||||
radius = 0.15
|
|
||||||
height = 0.02
|
|
||||||
|
|
||||||
[node name="CSGCombiner3D2" type="CSGCombiner3D" parent="Plates" unique_id=404631280]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.0762081, 0)
|
|
||||||
autosmooth = true
|
|
||||||
smoothing_angle = 103.9
|
|
||||||
|
|
||||||
[node name="CSGCylinder3D" type="CSGCylinder3D" parent="Plates/CSGCombiner3D2" unique_id=943162425]
|
|
||||||
radius = 0.2
|
|
||||||
height = 0.03
|
|
||||||
sides = 16
|
|
||||||
|
|
||||||
[node name="CSGCylinder3D" type="CSGCylinder3D" parent="Plates/CSGCombiner3D2/CSGCylinder3D" unique_id=218364524]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.010312311, 0)
|
|
||||||
operation = 2
|
|
||||||
radius = 0.15
|
|
||||||
height = 0.03
|
|
||||||
sides = 16
|
|
||||||
|
|
||||||
[node name="CSGCylinder3D2" type="CSGCylinder3D" parent="Plates/CSGCombiner3D2" unique_id=1548327331]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.027119078, 0)
|
|
||||||
radius = 0.15
|
|
||||||
height = 0.02
|
|
||||||
|
|
||||||
[node name="CSGCombiner3D3" type="CSGCombiner3D" parent="Plates" unique_id=1506211353]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.1214186, 0)
|
|
||||||
autosmooth = true
|
|
||||||
smoothing_angle = 103.9
|
|
||||||
|
|
||||||
[node name="CSGCylinder3D" type="CSGCylinder3D" parent="Plates/CSGCombiner3D3" unique_id=739830577]
|
|
||||||
radius = 0.2
|
|
||||||
height = 0.03
|
|
||||||
sides = 16
|
|
||||||
|
|
||||||
[node name="CSGCylinder3D" type="CSGCylinder3D" parent="Plates/CSGCombiner3D3/CSGCylinder3D" unique_id=1882120753]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.010312311, 0)
|
|
||||||
operation = 2
|
|
||||||
radius = 0.15
|
|
||||||
height = 0.03
|
|
||||||
sides = 16
|
|
||||||
|
|
||||||
[node name="CSGCylinder3D2" type="CSGCylinder3D" parent="Plates/CSGCombiner3D3" unique_id=1904629745]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.027119078, 0)
|
|
||||||
radius = 0.15
|
|
||||||
height = 0.02
|
|
||||||
@@ -1,98 +0,0 @@
|
|||||||
[gd_scene format=3 uid="uid://cwnwo4i28upap"]
|
|
||||||
|
|
||||||
[ext_resource type="Script" uid="uid://0y6wnjcsum6" path="res://Stations/item_dispenser.gd" id="1_gkb3v"]
|
|
||||||
[ext_resource type="PackedScene" uid="uid://dpot5qie20vf6" path="res://Items/burger.tscn" id="2_mep2a"]
|
|
||||||
[ext_resource type="Script" uid="uid://cquqe4f1m1sw6" path="res://addons/godot-xr-tools/objects/snap_zone.gd" id="3_3xuvi"]
|
|
||||||
[ext_resource type="Texture2D" uid="uid://cexxfyw03hr81" path="res://Textures/1.png" id="4_1f5le"]
|
|
||||||
[ext_resource type="PackedScene" uid="uid://mpapt5mkbuao" path="res://Prefabs/slide_off_dome.tscn" id="5_mep2a"]
|
|
||||||
|
|
||||||
[sub_resource type="SphereShape3D" id="SphereShape3D_xmbo2"]
|
|
||||||
radius = 0.3
|
|
||||||
|
|
||||||
[sub_resource type="CylinderShape3D" id="CylinderShape3D_24d3s"]
|
|
||||||
radius = 0.3
|
|
||||||
|
|
||||||
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_di04w"]
|
|
||||||
albedo_texture = ExtResource("4_1f5le")
|
|
||||||
|
|
||||||
[node name="RawBurgerDispenser" type="StaticBody3D" unique_id=235630131]
|
|
||||||
script = ExtResource("1_gkb3v")
|
|
||||||
item_scene = ExtResource("2_mep2a")
|
|
||||||
|
|
||||||
[node name="XRToolsSnapZone" type="Area3D" parent="." unique_id=1523586273]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.00070536137, 1.0645258, -0.002165556)
|
|
||||||
collision_layer = 65536
|
|
||||||
collision_mask = 65536
|
|
||||||
script = ExtResource("3_3xuvi")
|
|
||||||
snap_mode = 1
|
|
||||||
metadata/_custom_type_script = "uid://cquqe4f1m1sw6"
|
|
||||||
|
|
||||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="XRToolsSnapZone" unique_id=2105824734]
|
|
||||||
shape = SubResource("SphereShape3D_xmbo2")
|
|
||||||
|
|
||||||
[node name="SlideOffDome" parent="." unique_id=1427609426 instance=ExtResource("5_mep2a")]
|
|
||||||
|
|
||||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="." unique_id=378049928]
|
|
||||||
shape = SubResource("CylinderShape3D_24d3s")
|
|
||||||
|
|
||||||
[node name="CSGCombiner3D" type="CSGCombiner3D" parent="." unique_id=1275577257]
|
|
||||||
|
|
||||||
[node name="CSGCylinder3D" type="CSGCylinder3D" parent="CSGCombiner3D" unique_id=1973748218]
|
|
||||||
radius = 0.3
|
|
||||||
sides = 32
|
|
||||||
|
|
||||||
[node name="CSGCylinder3D2" type="CSGCylinder3D" parent="CSGCombiner3D" unique_id=590219609]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 0.9532462, 0.30219492, 0, -0.30219492, 0.9532462, -0.1276815, 1.0521446, -0.052202225)
|
|
||||||
radius = 0.08300781
|
|
||||||
height = 0.028435059
|
|
||||||
sides = 16
|
|
||||||
material = SubResource("StandardMaterial3D_di04w")
|
|
||||||
|
|
||||||
[node name="CSGCylinder3D3" type="CSGCylinder3D" parent="CSGCombiner3D" unique_id=177377476]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 0.9694763, 0.245185, 0, -0.245185, 0.9694763, 0.08106685, 1.0391599, -0.119440794)
|
|
||||||
radius = 0.08300781
|
|
||||||
height = 0.03
|
|
||||||
sides = 16
|
|
||||||
material = SubResource("StandardMaterial3D_di04w")
|
|
||||||
|
|
||||||
[node name="CSGCylinder3D4" type="CSGCylinder3D" parent="CSGCombiner3D" unique_id=622291452]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.19005477, 1.0198405, 0.049397707)
|
|
||||||
radius = 0.08300781
|
|
||||||
height = 0.03
|
|
||||||
sides = 16
|
|
||||||
material = SubResource("StandardMaterial3D_di04w")
|
|
||||||
|
|
||||||
[node name="CSGCylinder3D5" type="CSGCylinder3D" parent="CSGCombiner3D" unique_id=703594207]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.026051283, 1.0175319, 0.0042250156)
|
|
||||||
radius = 0.08300781
|
|
||||||
height = 0.03
|
|
||||||
sides = 16
|
|
||||||
material = SubResource("StandardMaterial3D_di04w")
|
|
||||||
|
|
||||||
[node name="CSGCylinder3D6" type="CSGCylinder3D" parent="CSGCombiner3D" unique_id=955808722]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.05739355, 1.0197641, 0.13219571)
|
|
||||||
radius = 0.08300781
|
|
||||||
height = 0.03
|
|
||||||
sides = 16
|
|
||||||
material = SubResource("StandardMaterial3D_di04w")
|
|
||||||
|
|
||||||
[node name="CSGCylinder3D7" type="CSGCylinder3D" parent="CSGCombiner3D" unique_id=1066788957]
|
|
||||||
transform = Transform3D(0.9111114, 0.40515354, 0.075673, -0.41123694, 0.8813372, 0.2326565, 0.027568169, -0.24309555, 0.9696106, 0.14799988, 1.0345665, 0.11710405)
|
|
||||||
radius = 0.08300781
|
|
||||||
height = 0.03
|
|
||||||
sides = 16
|
|
||||||
material = SubResource("StandardMaterial3D_di04w")
|
|
||||||
|
|
||||||
[node name="CSGCylinder3D8" type="CSGCylinder3D" parent="CSGCombiner3D" unique_id=553053058]
|
|
||||||
transform = Transform3D(0.9541017, 0.29948288, 0, -0.29948288, 0.9541017, 0, 0, 0, 1, 0.041060925, 1.0337045, 0.18304396)
|
|
||||||
radius = 0.08300781
|
|
||||||
height = 0.03
|
|
||||||
sides = 16
|
|
||||||
material = SubResource("StandardMaterial3D_di04w")
|
|
||||||
|
|
||||||
[node name="CSGCylinder3D9" type="CSGCylinder3D" parent="CSGCombiner3D" unique_id=980376661]
|
|
||||||
transform = Transform3D(0.8510151, 0.22759955, 0.47325662, -0.16729629, 0.97174567, -0.16649997, -0.49778044, 0.06251989, 0.8650468, 0.2036674, 1.0335208, -0.024382353)
|
|
||||||
radius = 0.08300781
|
|
||||||
height = 0.03
|
|
||||||
sides = 16
|
|
||||||
material = SubResource("StandardMaterial3D_di04w")
|
|
||||||
@@ -1,68 +0,0 @@
|
|||||||
extends StaticBody3D
|
|
||||||
|
|
||||||
const plate_wash_time: float = 3.0
|
|
||||||
@export_range(0.0, 10.0, 0.1) var wash_speed: float = 1.0
|
|
||||||
|
|
||||||
@onready var snap_zone: XRToolsSnapZone = $XRToolsSnapZone
|
|
||||||
@onready var progress_bar: ProgressBar3D = $ProgressBar3D
|
|
||||||
|
|
||||||
var time_washed: float = 0.0
|
|
||||||
var is_washing: bool = false
|
|
||||||
var plate: PlateController = null
|
|
||||||
|
|
||||||
func _ready() -> void:
|
|
||||||
if not progress_bar or progress_bar is not ProgressBar3D:
|
|
||||||
push_error("Sink missing reference to progressbar, or wrong type:", progress_bar)
|
|
||||||
|
|
||||||
snap_zone.has_picked_up.connect(_on_object_picked_up)
|
|
||||||
snap_zone.has_dropped.connect(_on_object_dropped)
|
|
||||||
progress_bar.override_fill_color(Color.DODGER_BLUE)
|
|
||||||
_refresh_progress_bar()
|
|
||||||
|
|
||||||
|
|
||||||
func _refresh_progress_bar() -> void:
|
|
||||||
progress_bar.set_progress(clampf(float(time_washed) / plate_wash_time, 0.0, 1.0))
|
|
||||||
progress_bar.set_bar_visible(is_washing)
|
|
||||||
|
|
||||||
|
|
||||||
func _on_object_picked_up(_item) -> void:
|
|
||||||
print("Sink: object picked up: ", _item)
|
|
||||||
plate = _item.get_node_or_null("PlateController") as PlateController
|
|
||||||
if plate:
|
|
||||||
is_washing = plate.is_dirty
|
|
||||||
if is_washing:
|
|
||||||
$AnimationPlayer.play("working")
|
|
||||||
$bubbles.show()
|
|
||||||
$water.show()
|
|
||||||
$GPUParticles3D.show()
|
|
||||||
|
|
||||||
|
|
||||||
func _on_object_dropped() -> void:
|
|
||||||
print("Sink: object drop ")
|
|
||||||
_reset_sink()
|
|
||||||
|
|
||||||
|
|
||||||
func _reset_sink():
|
|
||||||
time_washed = 0
|
|
||||||
is_washing = false
|
|
||||||
plate = null
|
|
||||||
$AnimationPlayer.play("RESET")
|
|
||||||
$water.hide()
|
|
||||||
$bubbles.hide()
|
|
||||||
$GPUParticles3D.hide()
|
|
||||||
_refresh_progress_bar()
|
|
||||||
|
|
||||||
func complete_washing():
|
|
||||||
plate.is_dirty = false
|
|
||||||
_reset_sink()
|
|
||||||
print("Sink washing complete!")
|
|
||||||
|
|
||||||
|
|
||||||
func _process(delta: float) -> void:
|
|
||||||
if is_washing:
|
|
||||||
time_washed += wash_speed * delta
|
|
||||||
_refresh_progress_bar()
|
|
||||||
print("Sink washing plate: ", time_washed)
|
|
||||||
|
|
||||||
if time_washed >= plate_wash_time:
|
|
||||||
complete_washing()
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
uid://byh5j25mwt3oc
|
|
||||||
File diff suppressed because one or more lines are too long
@@ -1,223 +0,0 @@
|
|||||||
class_name Table
|
|
||||||
extends StaticBody3D
|
|
||||||
|
|
||||||
const GAME_MANAGER = preload("res://GameManager.gd")
|
|
||||||
|
|
||||||
@export var thinking_duration: float = 6
|
|
||||||
@export var primary_duration: float = 23
|
|
||||||
@export var friend_duration: float = 10
|
|
||||||
@export var eating_duration: float = 4
|
|
||||||
|
|
||||||
@onready var label_3d: Label3D = $Label3D
|
|
||||||
@onready var label_3d_time: Label3D = $Label3DTime
|
|
||||||
@onready var snap_zones: Array[XRToolsSnapZone] = []
|
|
||||||
@onready var progress_bar: ProgressBar3D = $ProgressBar3D
|
|
||||||
|
|
||||||
const lbl_thinking: String = "..."
|
|
||||||
const lbl_gameover: String = "Game Over!"
|
|
||||||
const lbl_eating: String = "Eating..."
|
|
||||||
|
|
||||||
### Finite State Machine ####
|
|
||||||
|
|
||||||
enum TableState {
|
|
||||||
EMPTY, # Just finished eating or havent eaten yet
|
|
||||||
THINKING,
|
|
||||||
WAITING_PRIMARY, # Inital wait to be served
|
|
||||||
WAITING_FRIEND, # Waiting for friends food to arrive
|
|
||||||
EATING
|
|
||||||
}
|
|
||||||
|
|
||||||
## State is server-authoritative and synced (see table.tscn's Sync node);
|
|
||||||
## state transitions only ever run where NetworkManager.owns_world() is true
|
|
||||||
## (the whole station's _process is gated off elsewhere for non-owners, see
|
|
||||||
## NetworkManager._gate_station). The setters below just refresh the display,
|
|
||||||
## so both the server (via _setState) and clients (via incoming sync) show
|
|
||||||
## the same text. Use _setState(), never assign _state directly.
|
|
||||||
var _state: TableState = TableState.EMPTY: set = _set_state
|
|
||||||
var _state_time: float = 0.0: set = _set_state_time
|
|
||||||
var _state_duration: float = 0.0 # set in _set_state_time
|
|
||||||
var _unsatisfied_orders: Array[String] = []: set = _set_unsatisfied_orders
|
|
||||||
|
|
||||||
|
|
||||||
func _ready() -> void:
|
|
||||||
if not label_3d:
|
|
||||||
push_error("Table is missing reference to Label3D")
|
|
||||||
if not label_3d_time:
|
|
||||||
push_error("Table is missing reference to Label3DTime")
|
|
||||||
if not progress_bar or progress_bar is not ProgressBar3D:
|
|
||||||
push_error("Hob missing reference to progressbar, or wrong type:", progress_bar)
|
|
||||||
progress_bar.y_billboard = true
|
|
||||||
|
|
||||||
# Get snap_zones for plates, store in array snap_zones
|
|
||||||
for child in get_children():
|
|
||||||
var snap_zone_node = child as XRToolsSnapZone
|
|
||||||
if snap_zone_node:
|
|
||||||
snap_zones.append(snap_zone_node)
|
|
||||||
|
|
||||||
if snap_zones.is_empty():
|
|
||||||
push_error("Table is missing XRToolsSnapZone children")
|
|
||||||
return
|
|
||||||
|
|
||||||
for snap_zone_node in snap_zones:
|
|
||||||
snap_zone_node.has_picked_up.connect(_on_object_picked_up)
|
|
||||||
snap_zone_node.has_dropped.connect(_on_object_dropped)
|
|
||||||
_setState(TableState.EMPTY)
|
|
||||||
|
|
||||||
|
|
||||||
func _on_object_picked_up(_item) -> void:
|
|
||||||
print("Table: object picked up: ", _item)
|
|
||||||
_absorb_item_if_correct(_item)
|
|
||||||
|
|
||||||
|
|
||||||
func _on_object_dropped() -> void:
|
|
||||||
print("Table: object dropped ")
|
|
||||||
|
|
||||||
|
|
||||||
func _get_plate_from_item(_item: Node) -> PlateController:
|
|
||||||
return _item.get_children().filter(func(c): return c is PlateController).front() as PlateController
|
|
||||||
|
|
||||||
|
|
||||||
func _absorb_item_if_correct(_item: Node) -> void:
|
|
||||||
# Get plate controller in childer of _item (hopefully a plate XRpickable)
|
|
||||||
var plate = _get_plate_from_item(_item)
|
|
||||||
if not plate:
|
|
||||||
print("Table: held object is not a Plate")
|
|
||||||
return
|
|
||||||
print("Table: held a Plate!")
|
|
||||||
|
|
||||||
# Absorm items from the plate we want
|
|
||||||
for food_item in plate.container.contained_items:
|
|
||||||
print("Table: held a plate with FoodItem: ", food_item.id)
|
|
||||||
if food_item.id in _unsatisfied_orders:
|
|
||||||
print("Table: held FoodItem is in unsatisfied orders, removing it")
|
|
||||||
_unsatisfied_orders.erase(food_item.id)
|
|
||||||
GAME_MANAGER.money += food_item.sell_value
|
|
||||||
_setState(TableState.WAITING_FRIEND)
|
|
||||||
|
|
||||||
# Table has everything it wants. Start eating
|
|
||||||
if _unsatisfied_orders.is_empty():
|
|
||||||
_setState(TableState.EATING)
|
|
||||||
|
|
||||||
|
|
||||||
func place_order() -> void:
|
|
||||||
print("Table: place_order()")
|
|
||||||
_unsatisfied_orders.append(GAME_MANAGER.get_random_meal())
|
|
||||||
_unsatisfied_orders.append(GAME_MANAGER.get_random_meal())
|
|
||||||
|
|
||||||
|
|
||||||
func satisfyAllOrders() -> void:
|
|
||||||
print("Table: satisfyAllOrders()")
|
|
||||||
_unsatisfied_orders.clear()
|
|
||||||
clearAllPlates()
|
|
||||||
_setState(TableState.EMPTY)
|
|
||||||
|
|
||||||
|
|
||||||
func clearAllPlates() -> void:
|
|
||||||
print("Table: clearAllPlates()")
|
|
||||||
for snap_zone_node in snap_zones:
|
|
||||||
var held_object = snap_zone_node.picked_up_object
|
|
||||||
if not held_object:
|
|
||||||
continue
|
|
||||||
|
|
||||||
var plate = _get_plate_from_item(held_object)
|
|
||||||
if plate:
|
|
||||||
plate.container.clear()
|
|
||||||
plate.is_dirty = true
|
|
||||||
|
|
||||||
## Server-only state transition: sets the new state's timer and assigns
|
|
||||||
## _state (whose setter refreshes the display on every peer).
|
|
||||||
func _setState(newState: TableState) -> void:
|
|
||||||
print("Table set _state: ", TableState.keys()[newState])
|
|
||||||
|
|
||||||
match newState:
|
|
||||||
TableState.EMPTY:
|
|
||||||
_state_time = 0.0
|
|
||||||
_state_duration = 0.0
|
|
||||||
TableState.THINKING:
|
|
||||||
_state_time = eating_duration
|
|
||||||
_state_duration = eating_duration # Can't be done in _set_state(), will set duration inside timer
|
|
||||||
TableState.WAITING_PRIMARY:
|
|
||||||
_state_time = primary_duration
|
|
||||||
_state_duration = primary_duration
|
|
||||||
TableState.WAITING_FRIEND:
|
|
||||||
_state_time = friend_duration
|
|
||||||
_state_duration = friend_duration
|
|
||||||
TableState.EATING:
|
|
||||||
_state_time = eating_duration
|
|
||||||
_state_duration = eating_duration
|
|
||||||
|
|
||||||
_state = newState
|
|
||||||
|
|
||||||
|
|
||||||
## Pure presentation, driven off the current (locally authoritative or
|
|
||||||
## synced-from-server) state. Runs on every peer.
|
|
||||||
func _refresh_display() -> void:
|
|
||||||
match _state:
|
|
||||||
TableState.EMPTY:
|
|
||||||
progress_bar.set_bar_visible(false)
|
|
||||||
label_3d.text = "empty"
|
|
||||||
TableState.THINKING:
|
|
||||||
progress_bar.set_bar_visible(false)
|
|
||||||
label_3d.text = lbl_thinking
|
|
||||||
TableState.WAITING_PRIMARY:
|
|
||||||
label_3d.text = "%s\n%s" % [TableState.keys()[_state], "\n".join(_unsatisfied_orders)]
|
|
||||||
progress_bar.set_bar_visible(true)
|
|
||||||
progress_bar.override_fill_color(Color.RED if _state_time < 10 else Color.YELLOW)
|
|
||||||
TableState.WAITING_FRIEND:
|
|
||||||
label_3d.text = "%s\n%s" % [TableState.keys()[_state], "\n".join(_unsatisfied_orders)]
|
|
||||||
progress_bar.set_bar_visible(true)
|
|
||||||
progress_bar.override_fill_color(Color.RED if _state_time < 5 else Color.YELLOW)
|
|
||||||
TableState.EATING:
|
|
||||||
label_3d.text = lbl_eating
|
|
||||||
progress_bar.set_bar_visible(false)
|
|
||||||
|
|
||||||
label_3d_time.text = "%.1f" % _state_time
|
|
||||||
progress_bar.set_progress(clampf(float(_state_time) / _state_duration, 0.0, 1.0))
|
|
||||||
|
|
||||||
|
|
||||||
func _set_state(value: TableState) -> void:
|
|
||||||
_state = value
|
|
||||||
_refresh_display()
|
|
||||||
|
|
||||||
|
|
||||||
func _set_state_time(value: float) -> void:
|
|
||||||
_state_time = value
|
|
||||||
_refresh_display()
|
|
||||||
|
|
||||||
|
|
||||||
func _set_unsatisfied_orders(value: Array[String]) -> void:
|
|
||||||
_unsatisfied_orders = value
|
|
||||||
_refresh_display()
|
|
||||||
|
|
||||||
|
|
||||||
func _process(delta: float) -> void:
|
|
||||||
# Wait for state to finish
|
|
||||||
if _state_time > 0:
|
|
||||||
_state_time -= delta
|
|
||||||
return
|
|
||||||
|
|
||||||
if GAME_MANAGER.game_state == GAME_MANAGER.GameState.GAME_OVER:
|
|
||||||
return
|
|
||||||
|
|
||||||
# When state timer is finished, do this stuff before moving to next state
|
|
||||||
match _state:
|
|
||||||
TableState.EMPTY:
|
|
||||||
_setState(TableState.THINKING)
|
|
||||||
|
|
||||||
TableState.THINKING:
|
|
||||||
place_order()
|
|
||||||
_setState(TableState.WAITING_PRIMARY)
|
|
||||||
|
|
||||||
|
|
||||||
TableState.WAITING_PRIMARY:
|
|
||||||
label_3d.text = lbl_gameover
|
|
||||||
GAME_MANAGER.game_over()
|
|
||||||
|
|
||||||
TableState.WAITING_FRIEND:
|
|
||||||
label_3d.text = lbl_gameover
|
|
||||||
GAME_MANAGER.game_over()
|
|
||||||
|
|
||||||
|
|
||||||
TableState.EATING:
|
|
||||||
clearAllPlates()
|
|
||||||
_setState(TableState.EMPTY)
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
uid://caeikc7e3igkd
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user