Compare commits
7 Commits
d82f856b1a
...
7648ecbac9
| Author | SHA1 | Date | |
|---|---|---|---|
| 7648ecbac9 | |||
| bf31f85b02 | |||
| dbaad35e50 | |||
| 513ad23e09 | |||
| 9cdf72dc47 | |||
| cf4b4ac32e | |||
| f156379ff3 |
@@ -29,13 +29,13 @@ func _ready() -> void:
|
||||
func _on_body_entered(body: Node3D) -> void:
|
||||
if not NetworkManager.owns_world():
|
||||
return
|
||||
print("Container enabled: ", enabled)
|
||||
SweetLogger.debug("enabled: {0}", [enabled], "container.gd", "_on_body_entered")
|
||||
if not enabled:
|
||||
print("Container disabled in _on_body_entered body")
|
||||
SweetLogger.debug("disabled in _on_body_entered body", [], "container.gd", "_on_body_entered")
|
||||
return
|
||||
if not body.is_in_group(target_group):
|
||||
return
|
||||
print("Container _on_body_entered body: ", body)
|
||||
SweetLogger.debug("body: {0}", [body], "container.gd", "_on_body_entered")
|
||||
|
||||
|
||||
# If one of us is in a station
|
||||
@@ -46,14 +46,14 @@ func _on_body_entered(body: Node3D) -> void:
|
||||
|
||||
# If enough space, add item
|
||||
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])
|
||||
SweetLogger.debug("in station found {0} of type {1}: {2}", [target_group, FoodItem.Type.keys()[food_item.type], body.name], "container.gd", "_on_body_entered")
|
||||
var meal_count := contained_items.filter(func(f): return f.type == FoodItem.Type.MEAL).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")
|
||||
SweetLogger.debug("adding meal", [], "container.gd", "_on_body_entered")
|
||||
_add_item(body)
|
||||
if food_item.type == FoodItem.Type.SIDE and side_count < side_positions.size():
|
||||
print("Container adding side")
|
||||
SweetLogger.debug("adding side", [], "container.gd", "_on_body_entered")
|
||||
_add_item(body)
|
||||
|
||||
|
||||
@@ -93,7 +93,7 @@ func _add_item(item: Node3D) -> void:
|
||||
NetworkManager.despawn_item(item)
|
||||
# In case the container is on a table that needs to register this addition,
|
||||
# ask all table in scene to absorb any new items.
|
||||
print("Container group call absorb_items()")
|
||||
SweetLogger.debug("group call absorb_items()", [], "container.gd", "_add_item")
|
||||
get_tree().call_group("table", "absorb_items")
|
||||
|
||||
|
||||
|
||||
@@ -112,8 +112,8 @@ func _populate_world_if_owner() -> void:
|
||||
|
||||
|
||||
func _init_recipes():
|
||||
GameManager.meals_in_play = ["hamburger"]
|
||||
GameManager.sides_in_play = ["cube"]
|
||||
GameManager.set_meals_in_play(["hamburger"])
|
||||
GameManager.set_sides_in_play(["cube"])
|
||||
|
||||
|
||||
# Free the authored template nodes. Done immediately rather than with
|
||||
|
||||
+14
-33
@@ -18,7 +18,7 @@ var _pickable: XRToolsPickable
|
||||
# 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
|
||||
var _original_freeze_mode: RigidBody3D.FreezeMode
|
||||
|
||||
# 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.
|
||||
@@ -51,9 +51,7 @@ 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()
|
||||
])
|
||||
SweetLogger.debug("{0} net_held_by: {1} -> {2} (local state: {3}, authority={4})", [_pickable.name, old, value, _holder_desc(), get_multiplayer_authority()], "net_pickable.gd", "_set_net_held_by")
|
||||
apply_held_state()
|
||||
|
||||
|
||||
@@ -71,7 +69,7 @@ func _set_net_held_by(value: int) -> void:
|
||||
func apply_held_state() -> void:
|
||||
if not _pickable:
|
||||
return
|
||||
if not NetworkManager.is_online() or is_multiplayer_authority():
|
||||
if not NetworkManager.is_online() or (is_inside_tree() and 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
|
||||
@@ -84,12 +82,7 @@ func apply_held_state() -> void:
|
||||
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
|
||||
]
|
||||
)
|
||||
SweetLogger.debug("{0}: reclaiming ownership, restoring freeze_mode {1}->{2} collision_mask {3}->{4}", [_pickable.name, _pickable.freeze_mode, _original_freeze_mode, _pickable.collision_mask, _pickable.original_collision_mask], "net_pickable.gd", "apply_held_state")
|
||||
_pickable.freeze_mode = _original_freeze_mode
|
||||
_pickable.collision_mask = _pickable.original_collision_mask
|
||||
# Unlike freeze/collision (which XRToolsPickable manages itself while
|
||||
@@ -104,9 +97,7 @@ func apply_held_state() -> void:
|
||||
# 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
|
||||
])
|
||||
SweetLogger.debug("{0}: reclaiming ownership, restoring enabled {1}->{2}", [_pickable.name, _pickable.enabled, _original_enabled], "net_pickable.gd", "apply_held_state")
|
||||
_pickable.enabled = _original_enabled
|
||||
return
|
||||
# A net_held_by/position sync update can race ahead of the
|
||||
@@ -119,21 +110,13 @@ func apply_held_state() -> void:
|
||||
# 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
|
||||
]
|
||||
)
|
||||
SweetLogger.debug("{0}: ignoring non-authority sync (net_held_by={1}) — still actively held by our own hand (grab-race guard)", [_pickable.name, net_held_by], "net_pickable.gd", "apply_held_state")
|
||||
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
|
||||
]
|
||||
)
|
||||
SweetLogger.debug("{0}: was held by {1} on this peer, but authority now says peer {2} owns it — force-dropping", [_pickable.name, _holder_desc(), net_held_by], "net_pickable.gd", "apply_held_state")
|
||||
_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
|
||||
@@ -147,8 +130,8 @@ func apply_held_state() -> void:
|
||||
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])
|
||||
# if NetworkManager.is_online(): # This was spamming that Knife was frozen every frame.
|
||||
# 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
|
||||
@@ -165,10 +148,10 @@ func _on_picked_up(_p) -> void:
|
||||
# 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()])
|
||||
SweetLogger.debug("{0} picked up by {1} (not a hand) — no authority request", [_pickable.name, _holder_desc()], "net_pickable.gd", "_on_picked_up")
|
||||
return
|
||||
if NetworkManager.is_online():
|
||||
print("%s grabbed by hand (authority was peer %d), requesting authority" % [_pickable.name, net_held_by])
|
||||
SweetLogger.debug("{0} grabbed by hand (authority was peer {1}), requesting authority", [_pickable.name, net_held_by], "net_pickable.gd", "_on_picked_up")
|
||||
NetworkManager.request_item_authority_from(_pickable.get_path())
|
||||
|
||||
|
||||
@@ -177,12 +160,10 @@ func _on_dropped(_p) -> void:
|
||||
# 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])
|
||||
SweetLogger.debug("{0} dropped locally, but we aren't its authority (peer {1} is) — not reporting", [_pickable.name, net_held_by], "net_pickable.gd", "_on_dropped")
|
||||
return
|
||||
if NetworkManager.is_online():
|
||||
print("%s dropped, reporting release to server (lin=%s ang=%s)" % [
|
||||
_pickable.name, _pickable.linear_velocity, _pickable.angular_velocity
|
||||
])
|
||||
SweetLogger.debug("{0} dropped, reporting release to server (lin={1} ang={2})", [_pickable.name, _pickable.linear_velocity, _pickable.angular_velocity], "net_pickable.gd", "_on_dropped")
|
||||
# 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(
|
||||
@@ -205,5 +186,5 @@ func _holder_desc() -> String:
|
||||
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 "zone(%s)" % (str(station.name) if station else str(by.get_path()))
|
||||
return "other(%s: %s)" % [by.get_class(), by.get_path()]
|
||||
|
||||
@@ -331,7 +331,7 @@ func _try_snap_into_station(item: Node) -> void:
|
||||
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 "?"])
|
||||
log_line("skipped snapping %s: already held by %s (grab-race guard)" % [item.name, str(by.get_path()) if by else "?"])
|
||||
return
|
||||
for zone in _station_snap_zones():
|
||||
if is_instance_valid(zone.picked_up_object):
|
||||
@@ -522,7 +522,8 @@ func _on_player_absent(peer_id: int) -> void:
|
||||
# --- Command-line driven test bootstrap -----------------------------------
|
||||
|
||||
func _handle_cmdline() -> void:
|
||||
var args := OS.get_cmdline_user_args()
|
||||
SweetLogger.info("Networkmanager _handle_cmdline()", [], "network_manager.gd", "_handle_cmdline")
|
||||
var args := OS.get_cmdline_args()
|
||||
if args.has("--server"):
|
||||
log_line("cmdline: --server")
|
||||
host()
|
||||
@@ -553,7 +554,7 @@ func log_line(s: String) -> void:
|
||||
if p != null and p.get_connection_status() == MultiplayerPeer.CONNECTION_CONNECTED:
|
||||
id = multiplayer.get_unique_id()
|
||||
var line := "[NET %d] %s" % [id, s]
|
||||
print(line)
|
||||
SweetLogger.info(line, [], "network_manager.gd", "log_line")
|
||||
if _log_file:
|
||||
_log_file.store_line(line)
|
||||
_log_file.flush()
|
||||
|
||||
+2
-2
@@ -151,5 +151,5 @@ static func get_items_old() -> Array[Dictionary]:
|
||||
return items
|
||||
|
||||
|
||||
static func _item(scene: String, name: String, pos: Vector3) -> Dictionary:
|
||||
return {"scene": scene, "name": name, "xform": Transform3D(Basis(), pos), "props": {}}
|
||||
static func _item(scene: String, item_name: String, pos: Vector3) -> Dictionary:
|
||||
return {"scene": scene, "name": item_name, "xform": Transform3D(Basis(), pos), "props": {}}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[gd_scene load_steps=5 format=3]
|
||||
[gd_scene format=3 uid="uid://c58ns7csdahjy"]
|
||||
|
||||
[ext_resource type="Script" path="res://Player/net_player.gd" id="1_np001"]
|
||||
[ext_resource type="Script" uid="uid://bncuxh7j7ix5q" 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"]
|
||||
|
||||
@@ -28,17 +28,16 @@ properties/5/path = NodePath("RightHand:quaternion")
|
||||
properties/5/spawn = false
|
||||
properties/5/replication_mode = 1
|
||||
|
||||
[node name="NetPlayer" type="Node3D"]
|
||||
[node name="NetPlayer" type="Node3D" unique_id=70287099]
|
||||
script = ExtResource("1_np001")
|
||||
|
||||
[node name="Head" type="MeshInstance3D" parent="."]
|
||||
[node name="Head" type="MeshInstance3D" parent="." unique_id=56588259]
|
||||
mesh = SubResource("CapsuleMesh_np004")
|
||||
|
||||
[node name="LeftHand" parent="." instance=ExtResource("2_np002")]
|
||||
[node name="LeftHand" parent="." unique_id=1703673184 instance=ExtResource("2_np002")]
|
||||
|
||||
[node name="RightHand" parent="." instance=ExtResource("3_np003")]
|
||||
[node name="RightHand" parent="." unique_id=325341465 instance=ExtResource("3_np003")]
|
||||
|
||||
[node name="Sync" type="MultiplayerSynchronizer" parent="."]
|
||||
root_path = NodePath("..")
|
||||
replication_config = SubResource("SceneReplicationConfig_np005")
|
||||
[node name="Sync" type="MultiplayerSynchronizer" parent="." unique_id=529459963]
|
||||
replication_interval = 0.033
|
||||
replication_config = SubResource("SceneReplicationConfig_np005")
|
||||
|
||||
@@ -7,7 +7,7 @@ func _ready() -> void:
|
||||
|
||||
|
||||
func _on_game_state_changed(new_state: GameManager.GameState) -> void:
|
||||
print("BuildModeController: game_state_changed to %s" % GameManager.GameState.keys()[new_state])
|
||||
SweetLogger.info("game_state_changed to {0}", [GameManager.GameState.keys()[new_state]], "build_mode_controller.gd", "_on_game_state_changed")
|
||||
if new_state == GameManager.GameState.BUILDING:
|
||||
despawn_unheld_pickables()
|
||||
|
||||
@@ -25,7 +25,7 @@ func despawn_unheld_pickables():
|
||||
NetworkManager.despawn_item(pickable)
|
||||
continue
|
||||
if not held_by.is_in_group("persistent_inventory"):
|
||||
print("BuildModeController despawn_unheld_pickables held_by: %s, pickable: %s " % [held_by, pickable])
|
||||
SweetLogger.debug("despawn_unheld_pickables held_by: {0}, pickable: {1}", [held_by, pickable], "build_mode_controller.gd", "despawn_unheld_pickables")
|
||||
NetworkManager.despawn_item(pickable)
|
||||
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ var _food_item: FoodItem
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
print("CombinableItem _ready(): ", _pickable.name)
|
||||
SweetLogger.debug("_ready(): {0}", [_pickable.name], "combinable_item.gd", "_ready")
|
||||
_food_item = get_parent().get_node_or_null("FoodItem") as FoodItem
|
||||
if not _food_item:
|
||||
push_error("CombinableItem is missing FoodItem reference. must be a sibling of a FoodItem on ", get_parent().name, ".")
|
||||
@@ -40,8 +40,8 @@ func _ready() -> void:
|
||||
# Enable the trigger only while snapped into a snap zone (not hand-held).
|
||||
func _on_item_picked_up(_item: Node3D) -> void:
|
||||
var by := _pickable.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)
|
||||
var is_snapped: bool = by != null and by.has_method("is_xr_class") and by.is_xr_class("XRToolsSnapZone")
|
||||
set_deferred("monitoring", is_snapped)
|
||||
|
||||
func _on_item_dropped(_item: Node3D) -> void:
|
||||
set_deferred("monitoring", false)
|
||||
@@ -52,24 +52,24 @@ 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")
|
||||
SweetLogger.debug("other is our own pickable", [], "combinable_item.gd", "_on_body_entered")
|
||||
return
|
||||
|
||||
var other := Helper.find_food_item(body)
|
||||
if not other:
|
||||
print("CombinableItem _on_body_entered: other is not a foodItem")
|
||||
SweetLogger.debug("other is not a foodItem", [], "combinable_item.gd", "_on_body_entered")
|
||||
return
|
||||
|
||||
var result: PackedScene = RecipeManager.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])
|
||||
SweetLogger.debug("There is no recipe for {0} + {1}", [_food_item.id, other.id], "combinable_item.gd", "_on_body_entered")
|
||||
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, Helper.find_food_item(other_body).id, result.resource_path])
|
||||
SweetLogger.debug("combining {0} + {1} into {2}", [_food_item.id, Helper.find_food_item(other_body).id, result.resource_path], "combinable_item.gd", "_combine")
|
||||
|
||||
# Get Snapzone
|
||||
var snap_zone := _pickable.get_picked_up_by()
|
||||
|
||||
@@ -41,7 +41,7 @@ func _process(delta: float) -> void:
|
||||
# Count down to zero and despawn
|
||||
_time_left -= delta
|
||||
if _time_left <= 0:
|
||||
print("DespawningItem despawning!" , get_parent())
|
||||
SweetLogger.debug("despawning {0}", [get_parent()], "despawning_item.gd", "_process")
|
||||
NetworkManager.despawn_item(get_parent())
|
||||
# Stop counting: despawn_item() only queues the free, so without this we
|
||||
# keep re-reporting the same item every frame until it actually goes.
|
||||
|
||||
@@ -9,10 +9,10 @@ func _ready() -> void:
|
||||
if not kitchen_scene:
|
||||
push_error("StationSpawner missing kitchen_scene")
|
||||
|
||||
print("Kitchen init")
|
||||
SweetLogger.debug("initializing", [], "kitchen_instantiator.gd", "_ready")
|
||||
|
||||
if NetworkManager.owns_world():
|
||||
print("Kitchen init is_server")
|
||||
SweetLogger.debug("initializing on server", [], "kitchen_instantiator.gd", "_ready")
|
||||
# Later we will do procedural generation here.
|
||||
# For now we just load a scene.
|
||||
NetworkManager.call_deferred("spawn_item", kitchen_scene.resource_path, transform)
|
||||
|
||||
@@ -9,7 +9,7 @@ var customers_served: int = 0
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
GameManager.game_state = GameManager.GameState.BUILDING
|
||||
GameManager.set_game_state(GameManager.GameState.BUILDING)
|
||||
Signals.game_state_changed.connect(_on_game_state_changed)
|
||||
|
||||
|
||||
@@ -30,14 +30,14 @@ func _reset_values() -> void:
|
||||
|
||||
|
||||
func start_next_day() -> void:
|
||||
print("DayController: start_next_day")
|
||||
SweetLogger.info("starting next day", [], "day_controller.gd", "start_next_day")
|
||||
_reset_values()
|
||||
GameManager.customers_per_day += GameManager.customers_count_increase_per_day
|
||||
GameManager.day_number += 1
|
||||
GameManager.set_customers_per_day(GameManager.customers_per_day + GameManager.customers_count_increase_per_day)
|
||||
GameManager.set_day_number(GameManager.day_number + 1)
|
||||
|
||||
|
||||
func finish_current_day() -> void:
|
||||
print("DayController: finish_current_day")
|
||||
SweetLogger.info("finishing current day", [], "day_controller.gd", "finish_current_day")
|
||||
_reset_values()
|
||||
|
||||
|
||||
@@ -50,9 +50,9 @@ func _process(delta: float) -> void:
|
||||
#print("DayController: customers_at_this_time: ", customers_at_this_time)
|
||||
if customers_spawned < customers_at_this_time:
|
||||
customers_spawned += 1
|
||||
print("DayController: spawning customer")
|
||||
SweetLogger.debug("spawning customer", [], "day_controller.gd", "_process")
|
||||
Signals.request_customer_spawn.emit()
|
||||
# If day complete
|
||||
if GameManager.customers_per_day == customers_served and customers_spawned == GameManager.customers_per_day:
|
||||
print("DayController: Day complete")
|
||||
SweetLogger.info("day complete", [], "day_controller.gd", "_process")
|
||||
finish_current_day()
|
||||
|
||||
@@ -32,7 +32,7 @@ func spawn_customer() -> void:
|
||||
func _rebuild_table_list() -> void:
|
||||
_tables.clear()
|
||||
_tables.append_array(get_tree().get_nodes_in_group("table"))
|
||||
print("QueueController _rebuild_table_list complete: ", _tables)
|
||||
SweetLogger.debug("_rebuild_table_list complete: {0}", [_tables], "queue_controller.gd", "_rebuild_table_list")
|
||||
|
||||
|
||||
func _try_to_assign_customers() -> void:
|
||||
|
||||
+10
-10
@@ -114,14 +114,14 @@ func get_next(size, walls):
|
||||
var offset = [-1,-1]
|
||||
|
||||
walls.shuffle()
|
||||
print(size)
|
||||
SweetLogger.debug("get_next size: {0}", [size], "tile_map_layer.gd", "get_next")
|
||||
|
||||
for wall in walls:
|
||||
print(wall)
|
||||
SweetLogger.debug("get_next wall: {0}", [wall], "tile_map_layer.gd", "get_next")
|
||||
if wall["der"][1] == 0:
|
||||
print("horisontal")
|
||||
SweetLogger.debug("get_next horizontal wall", [], "tile_map_layer.gd", "get_next")
|
||||
if size[0]<wall["len"]-6:
|
||||
print("length 6 lees can go anywere")
|
||||
SweetLogger.debug("TileMapLayer get_next length 6 less can go anywhere", [], "tile_map_layer.gd", "get_next")
|
||||
if wall["der"][0] == 1:offset[1] = wall["pos"][1]
|
||||
else: offset[1] = wall["pos"][1]-size[1]
|
||||
|
||||
@@ -130,16 +130,16 @@ func get_next(size, walls):
|
||||
if size[0]+offset[0]>wall["pos"][0]+wall["len"]-3:offset[0] = wall["len"]-(3+size[0])
|
||||
|
||||
elif size[0]<=wall["len"]-3:
|
||||
print("3 less needs to be on a corner")
|
||||
SweetLogger.debug("TileMapLayer get_next 3 less needs to be on a corner", [], "tile_map_layer.gd", "get_next")
|
||||
if wall["der"][0] == 1:offset[1] = wall["pos"][1]
|
||||
else: offset[1] = wall["pos"][1]-size[1]
|
||||
|
||||
if randi_range(0, 1):offset[0]=wall["pos"][0]+wall["len"]-size[0]
|
||||
else:offset[0] = wall["pos"][0]
|
||||
else:
|
||||
print("virtical")
|
||||
SweetLogger.debug("get_next vertical wall", [], "tile_map_layer.gd", "get_next")
|
||||
if size[1]<wall["len"]-6:
|
||||
print("length 6 lees can go anywere")
|
||||
SweetLogger.debug("TileMapLayer get_next length 6 less can go anywhere", [], "tile_map_layer.gd", "get_next")
|
||||
if wall["der"][1] == 1:offset[0] = wall["pos"][0]
|
||||
else: offset[0] = wall["pos"][0]-size[0]
|
||||
|
||||
@@ -148,10 +148,10 @@ func get_next(size, walls):
|
||||
if size[1]+offset[1]>wall["len"]-3:offset[1] = wall["len"]-(3+size[1])
|
||||
|
||||
elif size[1]<=wall["len"]-3:
|
||||
print("3 less needs to be on a corner")
|
||||
SweetLogger.debug("TileMapLayer get_next 3 less needs to be on a corner", [], "tile_map_layer.gd", "get_next")
|
||||
if wall["der"][1] == 1:offset[0] = wall["pos"][0]
|
||||
else: offset[0] = wall["pos"][0]-size[0]
|
||||
print(offset)
|
||||
SweetLogger.debug("get_next offset: {0}", [offset], "tile_map_layer.gd", "get_next")
|
||||
|
||||
if randi() % 2:offset[1]=wall["pos"][1]+wall["len"]-size[1]
|
||||
else:offset[1] = wall["pos"][1]
|
||||
@@ -165,7 +165,7 @@ func get_next(size, walls):
|
||||
func draw_room(Size, offset=Vector2i(0, 0)):
|
||||
var walls = []
|
||||
offset = Vector2i(offset[0], offset[1])
|
||||
print("draw: ", Size, " offset: ", offset)
|
||||
SweetLogger.debug("draw_room size: {0} offset: {1}", [Size, offset], "tile_map_layer.gd", "draw_room")
|
||||
|
||||
for i in range(Size[0]):
|
||||
tile_map.set_cell(Vector2i(i+offset[0],offset[1]), 0, Vector2i(1,1))
|
||||
|
||||
@@ -6,6 +6,17 @@
|
||||
[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="SceneReplicationConfig" id="SceneReplicationConfig_u2p81"]
|
||||
properties/0/path = NodePath(".:position")
|
||||
properties/0/spawn = false
|
||||
properties/0/replication_mode = 1
|
||||
properties/1/path = NodePath(".:rotation")
|
||||
properties/1/spawn = false
|
||||
properties/1/replication_mode = 1
|
||||
properties/2/path = NodePath(".:visible")
|
||||
properties/2/spawn = false
|
||||
properties/2/replication_mode = 1
|
||||
|
||||
[sub_resource type="SphereShape3D" id="SphereShape3D_xmbo2"]
|
||||
radius = 0.3
|
||||
|
||||
@@ -21,6 +32,10 @@ albedo_color = Color(0.6784191, 0.54546416, 0.016760282, 1)
|
||||
[node name="StationMovement" parent="." unique_id=946873975 node_paths=PackedStringArray("station") instance=ExtResource("1_u2p81")]
|
||||
station = NodePath("../BurgerBunsDispenser")
|
||||
|
||||
[node name="MultiplayerSynchronizer" type="MultiplayerSynchronizer" parent="." unique_id=904562637]
|
||||
root_path = NodePath("../BurgerBunsDispenser")
|
||||
replication_config = SubResource("SceneReplicationConfig_u2p81")
|
||||
|
||||
[node name="BurgerBunsDispenser" type="StaticBody3D" parent="." unique_id=1720683779]
|
||||
script = ExtResource("1_myl3s")
|
||||
item_scene = ExtResource("2_1q74o")
|
||||
|
||||
@@ -9,6 +9,24 @@
|
||||
[ext_resource type="PackedScene" uid="uid://bxbocxdaayvwx" path="res://UI/progress_bar.tscn" id="6_racgh"]
|
||||
|
||||
[sub_resource type="SceneReplicationConfig" id="SceneReplicationConfig_3jbl6"]
|
||||
properties/0/path = NodePath("Counter:position")
|
||||
properties/0/spawn = false
|
||||
properties/0/replication_mode = 1
|
||||
properties/1/path = NodePath("Counter:rotation")
|
||||
properties/1/spawn = false
|
||||
properties/1/replication_mode = 1
|
||||
properties/2/path = NodePath("Counter:process_result")
|
||||
properties/2/spawn = false
|
||||
properties/2/replication_mode = 1
|
||||
properties/3/path = NodePath("Counter:process_result_work")
|
||||
properties/3/spawn = false
|
||||
properties/3/replication_mode = 1
|
||||
properties/4/path = NodePath("Counter:work_progress")
|
||||
properties/4/spawn = false
|
||||
properties/4/replication_mode = 1
|
||||
properties/5/path = NodePath("Counter:visible")
|
||||
properties/5/spawn = false
|
||||
properties/5/replication_mode = 1
|
||||
|
||||
[sub_resource type="BoxShape3D" id="BoxShape3D_24d3s"]
|
||||
size = Vector3(0.48521727, 0.040039063, 0.41994628)
|
||||
|
||||
+14
-12
@@ -8,14 +8,6 @@
|
||||
[ext_resource type="Material" uid="uid://d1djvskv4n4m3" path="res://textures/hob_off.tres" id="4_8qpxk"]
|
||||
[ext_resource type="Material" uid="uid://db7c7w4apwti7" path="res://textures/hob_on.tres" id="6_m7l4u"]
|
||||
|
||||
[sub_resource type="BoxShape3D" id="BoxShape3D_kdxnr"]
|
||||
size = Vector3(0.6, 1, 0.6)
|
||||
|
||||
[sub_resource type="BoxShape3D" id="BoxShape3D_7uuqv"]
|
||||
size = Vector3(0.6, 0.12802735, 0.6)
|
||||
|
||||
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_gkb3v"]
|
||||
|
||||
[sub_resource type="SceneReplicationConfig" id="SceneReplicationConfig_np_hob"]
|
||||
properties/0/path = NodePath("Hob:time_cooked")
|
||||
properties/0/spawn = false
|
||||
@@ -32,6 +24,17 @@ properties/3/replication_mode = 1
|
||||
properties/4/path = NodePath("Hob:rotation")
|
||||
properties/4/spawn = false
|
||||
properties/4/replication_mode = 1
|
||||
properties/5/path = NodePath("Hob:visible")
|
||||
properties/5/spawn = false
|
||||
properties/5/replication_mode = 1
|
||||
|
||||
[sub_resource type="BoxShape3D" id="BoxShape3D_kdxnr"]
|
||||
size = Vector3(0.6, 1, 0.6)
|
||||
|
||||
[sub_resource type="BoxShape3D" id="BoxShape3D_7uuqv"]
|
||||
size = Vector3(0.6, 0.12802735, 0.6)
|
||||
|
||||
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_gkb3v"]
|
||||
|
||||
[sub_resource type="Animation" id="Animation_7uuqv"]
|
||||
length = 0.001
|
||||
@@ -171,6 +174,9 @@ _data = {
|
||||
[node name="StationMovement" parent="." unique_id=946873975 node_paths=PackedStringArray("station") instance=ExtResource("1_pydjp")]
|
||||
station = NodePath("../Hob")
|
||||
|
||||
[node name="MultiplayerSynchronizer" type="MultiplayerSynchronizer" parent="." unique_id=768992259]
|
||||
replication_config = SubResource("SceneReplicationConfig_np_hob")
|
||||
|
||||
[node name="Hob" type="StaticBody3D" parent="." unique_id=1332123047]
|
||||
script = ExtResource("1_7jc4g")
|
||||
|
||||
@@ -279,10 +285,6 @@ size = Vector3(0.55, 0.835, 0.072)
|
||||
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="Hob" unique_id=768992259]
|
||||
root_path = NodePath("../..")
|
||||
replication_config = SubResource("SceneReplicationConfig_np_hob")
|
||||
|
||||
[node name="AnimationPlayer" type="AnimationPlayer" parent="Hob" unique_id=1525460719]
|
||||
root_node = NodePath("../..")
|
||||
libraries/ = SubResource("AnimationLibrary_ac5f3")
|
||||
|
||||
@@ -36,9 +36,6 @@ 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
|
||||
|
||||
[sub_resource type="BoxShape3D" id="BoxShape3D_vlqg6"]
|
||||
size = Vector3(0.5, 0.87231445, 0.5)
|
||||
@@ -51,10 +48,10 @@ albedo_color = Color(1, 0.78999996, 0.39999998, 0.4627451)
|
||||
properties/0/path = NodePath(".:visible")
|
||||
properties/0/spawn = false
|
||||
properties/0/replication_mode = 1
|
||||
properties/1/path = NodePath("../MoveHandle:position")
|
||||
properties/1/path = NodePath(".:position")
|
||||
properties/1/spawn = false
|
||||
properties/1/replication_mode = 1
|
||||
properties/2/path = NodePath("../MoveHandle:rotation")
|
||||
properties/2/path = NodePath(".:rotation")
|
||||
properties/2/spawn = false
|
||||
properties/2/replication_mode = 1
|
||||
|
||||
|
||||
+16
-16
@@ -11,9 +11,9 @@ extends StaticBody3D
|
||||
|
||||
# Chopping state. Follow the hob/sink pattern so the display refreshes when
|
||||
# values change; only the world owner runs the station's process in practice.
|
||||
var process_result: String = "": set = _set_result
|
||||
var process_result_work: float = 0.0: set = _set_result_work
|
||||
var work_progress: float = 0.0: set = _set_work_progress
|
||||
@export var process_result: String = "": set = _set_result
|
||||
@export var process_result_work: float = 0.0: set = _set_result_work
|
||||
@export var work_progress: float = 0.0: set = _set_work_progress
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
@@ -47,7 +47,7 @@ func _set_result(value: String) -> void:
|
||||
if not process_result.is_empty():
|
||||
knife.visible = true
|
||||
knife.enabled = true
|
||||
print("Counter: chopping recipe set: ", process_result)
|
||||
SweetLogger.debug("chopping recipe set: {0}", [process_result], "counter.gd", "_set_result")
|
||||
else:
|
||||
_hide_all_tools()
|
||||
|
||||
@@ -71,7 +71,7 @@ func _refresh_progress_bar() -> void:
|
||||
|
||||
# Add work from gesture area (knife hits). This increments the chopping progress.
|
||||
func add_work(work: float) -> void:
|
||||
print("Counter add_work: ", work)
|
||||
SweetLogger.debug("add_work: {0}", [work], "counter.gd", "add_work")
|
||||
# Only the world owner should drive the authoritative state. Guarding is
|
||||
# handled by higher-level NetworkManager logic elsewhere, mirror hob's
|
||||
# convert_held_to_item which checks ownership before spawning.
|
||||
@@ -82,16 +82,16 @@ func add_work(work: float) -> void:
|
||||
audio.play()
|
||||
# If we've reached the required time, convert the held item
|
||||
if process_result != "" and process_result_work > 0 and work_progress >= process_result_work:
|
||||
print("Counter: chopping complete, converting item to: ", process_result)
|
||||
SweetLogger.debug("chopping complete, converting item to: {0}", [process_result], "counter.gd", "add_work")
|
||||
work_progress = 0
|
||||
convert_held_to_item(process_result)
|
||||
|
||||
|
||||
func _on_gesture_area_body_entered(body: Node3D) -> void:
|
||||
print("Counter: gesture area entered: ", body)
|
||||
SweetLogger.debug("gesture area entered: {0}", [body], "counter.gd", "_on_gesture_area_body_entered")
|
||||
if body.is_in_group("chopping_tool"):
|
||||
if process_result == "":
|
||||
print("Counter: knife entered but nothing to chop")
|
||||
SweetLogger.debug("knife entered but nothing to chop", [], "counter.gd", "_on_gesture_area_body_entered")
|
||||
return
|
||||
|
||||
var speed := 0.0
|
||||
@@ -101,31 +101,31 @@ func _on_gesture_area_body_entered(body: Node3D) -> void:
|
||||
speed = body.velocity.length()
|
||||
|
||||
if speed < chop_min_speed:
|
||||
print("Counter: knife too slow for chopping: ", speed)
|
||||
SweetLogger.debug("knife too slow for chopping: {0}", [speed], "counter.gd", "_on_gesture_area_body_entered")
|
||||
return
|
||||
|
||||
add_work(chop_work_steps)
|
||||
|
||||
|
||||
func _on_object_picked_up(_item: Variant) -> void:
|
||||
print("Counter: object picked up: ", _item)
|
||||
SweetLogger.debug("object picked up: {0}", [_item], "counter.gd", "_on_object_picked_up")
|
||||
var food_item = Helper.find_food_item(_item)
|
||||
if not food_item:
|
||||
print("Counter: held object is not a FoodItem")
|
||||
SweetLogger.debug("held object is not a FoodItem", [], "counter.gd", "_on_object_picked_up")
|
||||
return
|
||||
|
||||
var result = RecipeManager.get_chopping_result(food_item.id)
|
||||
if not result:
|
||||
print("Counter: held a FoodItem that is not choppable, id: %s process_result: %s" % [food_item.id, result])
|
||||
SweetLogger.debug("held a FoodItem that is not choppable, id: {0} process_result: {1}", [food_item.id, result], "counter.gd", "_on_object_picked_up")
|
||||
return
|
||||
|
||||
process_result = result
|
||||
process_result_work = RecipeManager.get_chopping_work(food_item.id)
|
||||
print("Counter: set process_result ", process_result, " work: ", process_result_work)
|
||||
SweetLogger.debug("set process_result {0} work: {1}", [process_result, process_result_work], "counter.gd", "_on_object_picked_up")
|
||||
|
||||
|
||||
func _on_object_dropped(_item: Variant) -> void:
|
||||
print("Counter: object drop ")
|
||||
SweetLogger.debug("object drop", [], "counter.gd", "_on_object_dropped")
|
||||
work_progress = 0
|
||||
process_result = ""
|
||||
process_result_work = 0
|
||||
@@ -135,7 +135,7 @@ func _on_object_dropped(_item: Variant) -> void:
|
||||
func convert_held_to_item(_item: String) -> void:
|
||||
if not NetworkManager.owns_world():
|
||||
return
|
||||
print("Counter converting ", _item)
|
||||
SweetLogger.debug("converting {0}", [_item], "counter.gd", "convert_held_to_item")
|
||||
|
||||
var old_pickable = snap_zone.picked_up_object
|
||||
if not old_pickable:
|
||||
@@ -145,7 +145,7 @@ func convert_held_to_item(_item: String) -> void:
|
||||
var original_transform = old_pickable.global_transform
|
||||
var new_scene_instance = NetworkManager.spawn_item(RecipeManager.get_item_scene(_item).resource_path, original_transform)
|
||||
|
||||
print("Counter freeing old_pickable ", old_pickable)
|
||||
SweetLogger.debug("freeing old_pickable {0}", [old_pickable], "counter.gd", "convert_held_to_item")
|
||||
snap_zone.drop_object()
|
||||
NetworkManager.despawn_item(old_pickable)
|
||||
snap_zone.pick_up_object(new_scene_instance)
|
||||
|
||||
@@ -6,6 +6,17 @@
|
||||
[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="SceneReplicationConfig" id="SceneReplicationConfig_0wtc7"]
|
||||
properties/0/path = NodePath("CubeSideDispenser:position")
|
||||
properties/0/spawn = false
|
||||
properties/0/replication_mode = 1
|
||||
properties/1/path = NodePath("CubeSideDispenser:rotation")
|
||||
properties/1/spawn = false
|
||||
properties/1/replication_mode = 1
|
||||
properties/2/path = NodePath("CubeSideDispenser:visible")
|
||||
properties/2/spawn = false
|
||||
properties/2/replication_mode = 1
|
||||
|
||||
[sub_resource type="SphereShape3D" id="SphereShape3D_xmbo2"]
|
||||
radius = 0.3
|
||||
|
||||
@@ -25,6 +36,9 @@ size = Vector3(0.1, 0.1, 0.1)
|
||||
[node name="StationMovement" parent="." unique_id=946873975 node_paths=PackedStringArray("station") instance=ExtResource("1_qooyy")]
|
||||
station = NodePath("../CubeSideDispenser")
|
||||
|
||||
[node name="MultiplayerSynchronizer" type="MultiplayerSynchronizer" parent="." unique_id=821487160]
|
||||
replication_config = SubResource("SceneReplicationConfig_0wtc7")
|
||||
|
||||
[node name="CubeSideDispenser" type="StaticBody3D" parent="." unique_id=200950572]
|
||||
script = ExtResource("1_4m60m")
|
||||
item_scene = ExtResource("2_nn8tr")
|
||||
|
||||
@@ -11,7 +11,7 @@ func _makeDirty(item) -> void:
|
||||
return
|
||||
var plate: PlateController = item.get_node_or_null("PlateController") as PlateController
|
||||
if not plate:
|
||||
print("Dirt Station: held object is not a Plate")
|
||||
SweetLogger.debug("held object is not a Plate", [], "dirt_station.gd", "_makeDirty")
|
||||
return
|
||||
if not plate.is_dirty:
|
||||
plate.is_dirty = true
|
||||
|
||||
@@ -1,8 +1,20 @@
|
||||
[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="PackedScene" uid="uid://cvucwxibtol5f" path="res://stations/StationMovement.tscn" id="1_ucg2q"]
|
||||
[ext_resource type="Script" uid="uid://cquqe4f1m1sw6" path="res://addons/godot-xr-tools/objects/snap_zone.gd" id="2_v0ytd"]
|
||||
|
||||
[sub_resource type="SceneReplicationConfig" id="SceneReplicationConfig_ku4h3"]
|
||||
properties/0/path = NodePath(".:position")
|
||||
properties/0/spawn = false
|
||||
properties/0/replication_mode = 1
|
||||
properties/1/path = NodePath(".:rotation")
|
||||
properties/1/spawn = false
|
||||
properties/1/replication_mode = 1
|
||||
properties/2/path = NodePath(".:visible")
|
||||
properties/2/spawn = false
|
||||
properties/2/replication_mode = 1
|
||||
|
||||
[sub_resource type="BoxShape3D" id="BoxShape3D_24d3s"]
|
||||
size = Vector3(0.5, 1, 0.5)
|
||||
|
||||
@@ -16,28 +28,38 @@ 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"]]
|
||||
[node name="DirtStation" type="Node3D" unique_id=784427347]
|
||||
|
||||
[node name="StationMovement" parent="." unique_id=946873975 node_paths=PackedStringArray("station") instance=ExtResource("1_ucg2q")]
|
||||
station = NodePath("../DirtStation")
|
||||
|
||||
[node name="MultiplayerSynchronizer" type="MultiplayerSynchronizer" parent="." unique_id=1485614825]
|
||||
root_path = NodePath("../DirtStation")
|
||||
replication_config = SubResource("SceneReplicationConfig_ku4h3")
|
||||
|
||||
[node name="DirtStation" type="StaticBody3D" parent="." unique_id=160842153 groups=["station"]]
|
||||
script = ExtResource("1_hc1d4")
|
||||
|
||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="." unique_id=1400366312]
|
||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="DirtStation" unique_id=1400366312]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.5, 0)
|
||||
shape = SubResource("BoxShape3D_24d3s")
|
||||
|
||||
[node name="MeshInstance3D" type="MeshInstance3D" parent="CollisionShape3D" unique_id=55726639]
|
||||
[node name="MeshInstance3D" type="MeshInstance3D" parent="DirtStation/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]
|
||||
[node name="Label3D" type="Label3D" parent="DirtStation/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)
|
||||
[node name="XRToolsSnapZone" type="Area3D" parent="DirtStation" unique_id=333161027 groups=["station"]]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.0313971, 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]
|
||||
[node name="CollisionShape3D2" type="CollisionShape3D" parent="DirtStation/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")
|
||||
|
||||
+7
-7
@@ -67,26 +67,26 @@ func _refresh_display() -> void:
|
||||
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)
|
||||
SweetLogger.debug("object picked up: {0}", [_item], "hob.gd", "_on_object_picked_up")
|
||||
|
||||
# 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")
|
||||
SweetLogger.debug("held object is not a FoodItem", [], "hob.gd", "_on_object_picked_up")
|
||||
return
|
||||
var result = RecipeManager.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])
|
||||
SweetLogger.debug("held a FoodItem that is not cookable, id: {0} result: {1}", [_food_item.id, result], "hob.gd", "_on_object_picked_up")
|
||||
return
|
||||
|
||||
cooking_result = result
|
||||
cooking_result_time = RecipeManager.get_cooking_time(_food_item.id)
|
||||
print("Hob: set cooking_result ", cooking_result)
|
||||
SweetLogger.debug("set cooking_result {0}", [cooking_result], "hob.gd", "_on_object_picked_up")
|
||||
# The setters above already refresh the display and start the flames.
|
||||
|
||||
|
||||
func _on_object_dropped(_item) -> void:
|
||||
print("Hob: object drop ")
|
||||
SweetLogger.debug("object drop", [], "hob.gd", "_on_object_dropped")
|
||||
time_cooked = 0
|
||||
cooking_result = ""
|
||||
cooking_result_time = 0
|
||||
@@ -95,7 +95,7 @@ func _on_object_dropped(_item) -> void:
|
||||
func convert_held_to_item(_item: String) -> void:
|
||||
if not NetworkManager.owns_world():
|
||||
return
|
||||
print("Hob converting ", _item)
|
||||
SweetLogger.debug("converting {0}", [_item], "hob.gd", "convert_held_to_item")
|
||||
|
||||
var old_pickable = snap_zone.picked_up_object
|
||||
if not old_pickable:
|
||||
@@ -108,7 +108,7 @@ func convert_held_to_item(_item: String) -> void:
|
||||
var new_scene_instance = NetworkManager.spawn_item(RecipeManager.get_item_scene(_item).resource_path, original_transform)
|
||||
|
||||
# Drop and free the old item and pick up the new one
|
||||
print("Hob freeing old_pickable ", old_pickable)
|
||||
SweetLogger.debug("freeing old_pickable {0}", [old_pickable], "hob.gd", "convert_held_to_item")
|
||||
snap_zone.drop_object()
|
||||
NetworkManager.despawn_item(old_pickable)
|
||||
snap_zone.pick_up_object(new_scene_instance)
|
||||
|
||||
@@ -10,7 +10,7 @@ func _ready() -> void:
|
||||
push_error("Item dispenser is missing a reference to its snap zone child")
|
||||
|
||||
|
||||
func _process(delta: float) -> void:
|
||||
func _process(_delta: float) -> void:
|
||||
if not NetworkManager.owns_world():
|
||||
return
|
||||
#if snap_zone.picked_up_object: # Player picked up this station
|
||||
@@ -21,6 +21,6 @@ func _process(delta: float) -> void:
|
||||
#return
|
||||
#
|
||||
if not snap_zone.picked_up_object:
|
||||
print("Item dispenser is missing item, spawning new item")
|
||||
SweetLogger.debug("missing item, spawning new item", [], "item_dispenser.gd", "_process")
|
||||
var new_item = NetworkManager.spawn_item(item_scene.resource_path, snap_zone.global_transform)
|
||||
snap_zone.pick_up_object(new_item)
|
||||
|
||||
@@ -6,6 +6,17 @@
|
||||
[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="SceneReplicationConfig" id="SceneReplicationConfig_jgjsq"]
|
||||
properties/0/path = NodePath("PlateDispenser:position")
|
||||
properties/0/spawn = false
|
||||
properties/0/replication_mode = 1
|
||||
properties/1/path = NodePath("PlateDispenser:rotation")
|
||||
properties/1/spawn = false
|
||||
properties/1/replication_mode = 1
|
||||
properties/2/path = NodePath("PlateDispenser:visible")
|
||||
properties/2/spawn = false
|
||||
properties/2/replication_mode = 1
|
||||
|
||||
[sub_resource type="SphereShape3D" id="SphereShape3D_xmbo2"]
|
||||
radius = 0.3
|
||||
|
||||
@@ -18,6 +29,9 @@ radius = 0.3
|
||||
[node name="StationMovement" parent="." unique_id=946873975 node_paths=PackedStringArray("station") instance=ExtResource("1_jgjsq")]
|
||||
station = NodePath("../PlateDispenser")
|
||||
|
||||
[node name="MultiplayerSynchronizer" type="MultiplayerSynchronizer" parent="." unique_id=901684173]
|
||||
replication_config = SubResource("SceneReplicationConfig_jgjsq")
|
||||
|
||||
[node name="PlateDispenser" type="StaticBody3D" parent="." unique_id=710538846]
|
||||
script = ExtResource("1_jm0ik")
|
||||
item_scene = ExtResource("2_tfo2i")
|
||||
|
||||
@@ -6,6 +6,17 @@
|
||||
[ext_resource type="Script" uid="uid://cquqe4f1m1sw6" path="res://addons/godot-xr-tools/objects/snap_zone.gd" id="4_fx1kw"]
|
||||
[ext_resource type="PackedScene" uid="uid://mpapt5mkbuao" path="res://prefabs/slide_off_dome.tscn" id="5_ur331"]
|
||||
|
||||
[sub_resource type="SceneReplicationConfig" id="SceneReplicationConfig_8orw3"]
|
||||
properties/0/path = NodePath("PotatoDispenser:position")
|
||||
properties/0/spawn = false
|
||||
properties/0/replication_mode = 1
|
||||
properties/1/path = NodePath("PotatoDispenser:rotation")
|
||||
properties/1/spawn = false
|
||||
properties/1/replication_mode = 1
|
||||
properties/2/path = NodePath("PotatoDispenser:visible")
|
||||
properties/2/spawn = false
|
||||
properties/2/replication_mode = 1
|
||||
|
||||
[sub_resource type="SphereShape3D" id="SphereShape3D_xmbo2"]
|
||||
radius = 0.3
|
||||
|
||||
@@ -21,6 +32,9 @@ albedo_color = Color(0.48, 0.34336, 0.1872, 1)
|
||||
[node name="StationMovement" parent="." unique_id=946873975 node_paths=PackedStringArray("station") instance=ExtResource("1_8orw3")]
|
||||
station = NodePath("../PotatoDispenser")
|
||||
|
||||
[node name="MultiplayerSynchronizer" type="MultiplayerSynchronizer" parent="." unique_id=41449367]
|
||||
replication_config = SubResource("SceneReplicationConfig_8orw3")
|
||||
|
||||
[node name="PotatoDispenser" type="StaticBody3D" parent="." unique_id=1720683779]
|
||||
script = ExtResource("2_30d2d")
|
||||
item_scene = ExtResource("3_mjqsn")
|
||||
|
||||
@@ -7,6 +7,17 @@
|
||||
[ext_resource type="PackedScene" uid="uid://mpapt5mkbuao" path="res://prefabs/slide_off_dome.tscn" id="5_mep2a"]
|
||||
[ext_resource type="PackedScene" uid="uid://cvucwxibtol5f" path="res://stations/StationMovement.tscn" id="6_8ou8n"]
|
||||
|
||||
[sub_resource type="SceneReplicationConfig" id="SceneReplicationConfig_8ou8n"]
|
||||
properties/0/path = NodePath("RawBurgerDispenser:position")
|
||||
properties/0/spawn = false
|
||||
properties/0/replication_mode = 1
|
||||
properties/1/path = NodePath("RawBurgerDispenser:rotation")
|
||||
properties/1/spawn = false
|
||||
properties/1/replication_mode = 1
|
||||
properties/2/path = NodePath("RawBurgerDispenser:visible")
|
||||
properties/2/spawn = false
|
||||
properties/2/replication_mode = 1
|
||||
|
||||
[sub_resource type="SphereShape3D" id="SphereShape3D_xmbo2"]
|
||||
radius = 0.3
|
||||
|
||||
@@ -22,6 +33,9 @@ albedo_texture = ExtResource("4_1f5le")
|
||||
[node name="StationMovement" parent="." unique_id=946873975 node_paths=PackedStringArray("station") instance=ExtResource("6_8ou8n")]
|
||||
station = NodePath("../RawBurgerDispenser")
|
||||
|
||||
[node name="MultiplayerSynchronizer" type="MultiplayerSynchronizer" parent="." unique_id=1886082284]
|
||||
replication_config = SubResource("SceneReplicationConfig_8ou8n")
|
||||
|
||||
[node name="RawBurgerDispenser" type="StaticBody3D" parent="." unique_id=235630131]
|
||||
script = ExtResource("1_gkb3v")
|
||||
item_scene = ExtResource("2_mep2a")
|
||||
|
||||
+7
-7
@@ -10,9 +10,9 @@ const plate_wash_time: float = 3.0
|
||||
## display when they change. Only the world owner runs this station's _process
|
||||
## and snap zone, so without this a client never updates its bar — it stayed
|
||||
## frozen on screen long after the plate came out clean.
|
||||
var time_washed: float = 0.0: set = _set_time_washed
|
||||
var is_washing: bool = false: set = _set_is_washing
|
||||
var plate: PlateController = null
|
||||
@export var time_washed: float = 0.0: set = _set_time_washed
|
||||
@export var is_washing: bool = false: set = _set_is_washing
|
||||
@export var plate: PlateController = null
|
||||
|
||||
|
||||
func _set_time_washed(value: float) -> void:
|
||||
@@ -59,7 +59,7 @@ func _refresh_progress_bar() -> void:
|
||||
|
||||
|
||||
func _on_object_picked_up(_item) -> void:
|
||||
print("Sink: object picked up: ", _item)
|
||||
SweetLogger.debug("object picked up: {0}", [_item], "sink.gd", "_on_object_picked_up")
|
||||
plate = _item.get_node_or_null("PlateController") as PlateController
|
||||
if plate:
|
||||
# The setter starts the effects and shows the bar, here and on clients.
|
||||
@@ -67,7 +67,7 @@ func _on_object_picked_up(_item) -> void:
|
||||
|
||||
|
||||
func _on_object_dropped(_item) -> void:
|
||||
print("Sink: object drop ")
|
||||
SweetLogger.debug("object drop", [], "sink.gd", "_on_object_dropped")
|
||||
_reset_sink()
|
||||
|
||||
|
||||
@@ -81,14 +81,14 @@ func complete_washing():
|
||||
return
|
||||
plate.is_dirty = false
|
||||
_reset_sink()
|
||||
print("Sink washing complete!")
|
||||
SweetLogger.debug("washing complete!", [], "sink.gd", "complete_washing")
|
||||
|
||||
|
||||
func _process(delta: float) -> void:
|
||||
if is_washing:
|
||||
time_washed += wash_speed * delta
|
||||
_refresh_progress_bar()
|
||||
print("Sink washing plate: ", time_washed)
|
||||
SweetLogger.debug("washing plate: {0}", [time_washed], "sink.gd", "_process")
|
||||
|
||||
if time_washed >= plate_wash_time:
|
||||
complete_washing()
|
||||
|
||||
+21
-11
@@ -5,6 +5,23 @@
|
||||
[ext_resource type="Script" uid="uid://cquqe4f1m1sw6" path="res://addons/godot-xr-tools/objects/snap_zone.gd" id="2_3ocod"]
|
||||
[ext_resource type="PackedScene" uid="uid://bxbocxdaayvwx" path="res://UI/progress_bar.tscn" id="4_1pinr"]
|
||||
|
||||
[sub_resource type="SceneReplicationConfig" id="SceneReplicationConfig_np_sink"]
|
||||
properties/0/path = NodePath(".:position")
|
||||
properties/0/spawn = false
|
||||
properties/0/replication_mode = 1
|
||||
properties/1/path = NodePath(".:rotation")
|
||||
properties/1/spawn = false
|
||||
properties/1/replication_mode = 1
|
||||
properties/2/path = NodePath(".:time_washed")
|
||||
properties/2/spawn = false
|
||||
properties/2/replication_mode = 1
|
||||
properties/3/path = NodePath(".:is_washing")
|
||||
properties/3/spawn = false
|
||||
properties/3/replication_mode = 1
|
||||
properties/4/path = NodePath(".:visible")
|
||||
properties/4/spawn = false
|
||||
properties/4/replication_mode = 1
|
||||
|
||||
[sub_resource type="BoxShape3D" id="BoxShape3D_l02yb"]
|
||||
size = Vector3(0.6, 1.0024658, 0.6)
|
||||
|
||||
@@ -16,14 +33,6 @@ stereo = true
|
||||
[sub_resource type="BoxShape3D" id="BoxShape3D_ai6d4"]
|
||||
size = Vector3(0.5, 0.128, 0.5)
|
||||
|
||||
[sub_resource type="SceneReplicationConfig" id="SceneReplicationConfig_np_sink"]
|
||||
properties/0/path = NodePath(".:time_washed")
|
||||
properties/0/spawn = true
|
||||
properties/0/replication_mode = 1
|
||||
properties/1/path = NodePath(".:is_washing")
|
||||
properties/1/spawn = true
|
||||
properties/1/replication_mode = 1
|
||||
|
||||
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_0gbf8"]
|
||||
|
||||
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_bvwq1"]
|
||||
@@ -187,6 +196,10 @@ height = 0.04
|
||||
[node name="StationMovement" parent="." unique_id=946873975 node_paths=PackedStringArray("station") instance=ExtResource("1_uluvy")]
|
||||
station = NodePath("../Sink")
|
||||
|
||||
[node name="MultiplayerSynchronizer" type="MultiplayerSynchronizer" parent="." unique_id=1601242574]
|
||||
root_path = NodePath("../Sink")
|
||||
replication_config = SubResource("SceneReplicationConfig_np_sink")
|
||||
|
||||
[node name="Sink" type="StaticBody3D" parent="." unique_id=2055277359 groups=["station"]]
|
||||
script = ExtResource("1_7hh4b")
|
||||
|
||||
@@ -241,9 +254,6 @@ transform = Transform3D(1, 0, 0, 0, 0.9367828, -0.34991136, 0, 0.34991136, 0.936
|
||||
operation = 2
|
||||
size = Vector3(1, 1.2053223, 0.352417)
|
||||
|
||||
[node name="Sync" type="MultiplayerSynchronizer" parent="Sink" unique_id=1601242574]
|
||||
replication_config = SubResource("SceneReplicationConfig_np_sink")
|
||||
|
||||
[node name="ProgressBar3D" parent="Sink" unique_id=654673176 instance=ExtResource("4_1pinr")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.3229032, -0.035980098)
|
||||
|
||||
|
||||
+102
-24
@@ -7,17 +7,21 @@ extends Node
|
||||
|
||||
var move_handle_rigid: RigidBody3D
|
||||
var original_collision_layer: int = 0
|
||||
var original_y_pos: float = 0.0
|
||||
var original_handle_y_pos: float = 0.0
|
||||
var original_station_transform: Transform3D = Transform3D.IDENTITY
|
||||
var moving: bool = false
|
||||
@export var moving: bool = false
|
||||
var ghost_materials: Array[StandardMaterial3D] = []
|
||||
|
||||
# Ghost update throttling (clients send unreliable RPCs to server at this rate)
|
||||
var ghost_send_interval: float = 0.1 # seconds (10 Hz)
|
||||
var _ghost_send_accum: float = 0.0
|
||||
|
||||
const GHOST_COLOR_VALID: Color = Color(0, 1, 0, 0.35)
|
||||
const GHOST_COLOR_INVALID: Color = Color(1, 0, 0, 0.35)
|
||||
|
||||
|
||||
func set_move_handle_enabled(enabled: bool) -> void:
|
||||
print("StationMovement set_move_handle_enabled: ", enabled)
|
||||
SweetLogger.debug("set_move_handle_enabled: {0}", [enabled], "station_movement.gd", "set_move_handle_enabled")
|
||||
move_handle.visible = enabled
|
||||
move_handle.enabled = enabled
|
||||
if enabled:
|
||||
@@ -28,7 +32,7 @@ func _on_game_state_changed(new_state: GameManager.GameState) -> void:
|
||||
set_move_handle_enabled(new_state == GameManager.GameState.BUILDING)
|
||||
|
||||
func _on_station_bought(_instance: Node3D):
|
||||
print("StationMovement _on_station_bought")
|
||||
SweetLogger.info("_on_station_bought")
|
||||
if GameManager.game_state == GameManager.GameState.BUILDING:
|
||||
set_move_handle_enabled(true)
|
||||
|
||||
@@ -42,7 +46,7 @@ func _ready() -> void:
|
||||
|
||||
move_handle_rigid = move_handle as RigidBody3D
|
||||
original_collision_layer = station.collision_layer
|
||||
original_y_pos = move_handle.transform.origin.y
|
||||
original_handle_y_pos = move_handle.transform.origin.y
|
||||
original_station_transform = station.global_transform
|
||||
move_handle.picked_up.connect(_handle_pickup)
|
||||
move_handle.dropped.connect(_handle_drop)
|
||||
@@ -89,51 +93,75 @@ func _set_ghost_color(color: Color) -> void:
|
||||
|
||||
|
||||
func _handle_pickup(_by: Node) -> void:
|
||||
print("StationMovement handle pickup")
|
||||
SweetLogger.info("handle pickup")
|
||||
if move_handle.get_picked_up_by() is XRToolsSnapZone:
|
||||
print("StationMovement handle pickup by snap zone, dropping and resetting position")
|
||||
SweetLogger.info("handle pickup by snap zone, dropping and resetting position")
|
||||
move_handle.drop()
|
||||
move_handle.global_position = station.global_position + Vector3(0, original_y_pos, 0)
|
||||
move_handle.global_position = station.global_position + Vector3(0, original_handle_y_pos, 0)
|
||||
move_handle.rotation = station.rotation
|
||||
return
|
||||
|
||||
|
||||
moving = true
|
||||
move_ghost.visible = true
|
||||
station.visible = false
|
||||
station.collision_layer = 0
|
||||
original_station_transform = station.global_transform
|
||||
move_ghost.global_transform = original_station_transform
|
||||
if NetworkManager.is_online():
|
||||
# Ask the server to update visibility (reliable)
|
||||
server_update_visibility.rpc_id(1, true, false)
|
||||
else:
|
||||
# If not connected to server (single-player or test), apply locally
|
||||
move_ghost.visible = true
|
||||
station.visible = false
|
||||
|
||||
|
||||
func _handle_drop(_by: Node) -> void:
|
||||
print("StationMovement handle drop")
|
||||
SweetLogger.info("handle drop")
|
||||
moving = false
|
||||
move_ghost.visible = false
|
||||
station.visible = true
|
||||
station.collision_layer = original_collision_layer
|
||||
if _is_move_position_valid():
|
||||
station.global_transform = move_ghost.global_transform
|
||||
else:
|
||||
station.global_transform = original_station_transform
|
||||
move_handle.global_position = station.global_position + Vector3(0, original_y_pos, 0)
|
||||
move_handle.rotation = station.rotation
|
||||
|
||||
var is_valid: bool = _is_move_position_valid()
|
||||
if NetworkManager.is_online():
|
||||
server_handle_drop.rpc_id(1, move_ghost.global_transform, is_valid)
|
||||
else:
|
||||
# If not connected to server (single-player or test), apply locally only when valid
|
||||
if is_valid:
|
||||
station.global_transform = move_ghost.global_transform
|
||||
move_handle.global_transform = move_ghost.global_transform.translated(Vector3(0, original_handle_y_pos, 0))
|
||||
SweetLogger.debug("handle drop (local apply), station authority: {0} move_handle authority: {1}", [station.get_multiplayer_authority(), move_handle.get_multiplayer_authority()], "station_movement.gd", "_handle_drop")
|
||||
else:
|
||||
station.global_transform = original_station_transform
|
||||
move_handle.global_transform = original_station_transform.translated(Vector3(0, original_handle_y_pos, 0))
|
||||
SweetLogger.debug("handle drop (local reject), restoring original position", [], "station_movement.gd", "_handle_drop")
|
||||
|
||||
func _process(_delta: float) -> void:
|
||||
if not moving:
|
||||
return
|
||||
|
||||
# Update the ghost locally for instant feedback and send throttled unreliable RPCs to the server
|
||||
move_ghost.visible = true
|
||||
station.visible = false
|
||||
|
||||
move_ghost.global_transform = Helper.get_snapped_transform(move_handle)
|
||||
move_ghost.global_transform.origin.y = original_station_transform.origin.y
|
||||
if _is_move_position_valid():
|
||||
_set_ghost_color(GHOST_COLOR_VALID)
|
||||
else:
|
||||
_set_ghost_color(GHOST_COLOR_INVALID)
|
||||
|
||||
var ghost_color = GHOST_COLOR_VALID if _is_move_position_valid() else GHOST_COLOR_INVALID
|
||||
_set_ghost_color(ghost_color)
|
||||
|
||||
# Throttle and send ghost transform updates to server so other clients see the preview
|
||||
_ghost_send_accum += _delta
|
||||
if _ghost_send_accum >= ghost_send_interval:
|
||||
_ghost_send_accum = 0.0
|
||||
# Unreliable RPC to the server to update the server-side ghost; server will replicate to clients
|
||||
# Use rpc_unreliable_id to avoid blocking traffic
|
||||
if NetworkManager.is_online():
|
||||
server_update_move_ghost_transform.rpc_id(1, move_ghost.global_transform, ghost_color)
|
||||
|
||||
|
||||
func _is_move_position_valid() -> bool:
|
||||
for body in move_ghost.get_overlapping_bodies():
|
||||
print("Overlapping body: ", body)
|
||||
SweetLogger.debug("Overlapping body: {0}", [body], "station_movement.gd", "_is_move_position_valid")
|
||||
if body == move_handle:
|
||||
continue
|
||||
if body == station:
|
||||
@@ -146,9 +174,59 @@ func _is_move_position_valid() -> bool:
|
||||
return false
|
||||
|
||||
for area in move_ghost.get_overlapping_areas():
|
||||
print("Overlapping area: ", area)
|
||||
#print("Overlapping area: ", area)
|
||||
if area == move_ghost:
|
||||
continue
|
||||
return false
|
||||
|
||||
return true
|
||||
|
||||
|
||||
@rpc("any_peer", "call_remote", "reliable")
|
||||
func server_handle_drop(new_transform: Transform3D, client_thinks_valid: bool):
|
||||
if not multiplayer.is_server():
|
||||
return
|
||||
if not (client_thinks_valid):
|
||||
# Reset state for everyone, including server
|
||||
var original_trans = original_station_transform # Make a copy to avoid server_update_station_transform setting it before move handle uses it
|
||||
server_update_station_transform.rpc(original_trans)
|
||||
server_update_move_ghost_transform.rpc(original_trans)
|
||||
server_update_handle_transform.rpc(original_trans.translated(Vector3(0, original_handle_y_pos, 0)))
|
||||
server_update_visibility.rpc(false, true)
|
||||
SweetLogger.debug("server_handle_drop: transform rejected (invalid)", [], "station_movement.gd", "server_handle_drop")
|
||||
return
|
||||
|
||||
server_update_station_transform.rpc(new_transform)
|
||||
server_update_move_ghost_transform.rpc(new_transform)
|
||||
server_update_handle_transform.rpc(new_transform.translated(Vector3(0, original_handle_y_pos, 0)))
|
||||
server_update_visibility.rpc(false, true)
|
||||
|
||||
SweetLogger.debug("server_handle_drop: transform applied", [], "station_movement.gd", "server_handle_drop")
|
||||
|
||||
|
||||
@rpc("any_peer", "call_local", "reliable") # Server updates clients
|
||||
func server_update_station_transform(new_transform: Transform3D) -> void:
|
||||
SweetLogger.debug("server_update_station_transform", [], "station_movement.gd", "server_update_station_transform")
|
||||
station.global_transform = new_transform
|
||||
original_station_transform = new_transform
|
||||
|
||||
|
||||
@rpc("any_peer", "call_local", "reliable") # Server updates clients
|
||||
func server_update_handle_transform(new_transform: Transform3D) -> void:
|
||||
SweetLogger.debug("server_update_handle_transform", [], "station_movement.gd", "server_update_handle_transform")
|
||||
move_handle.global_transform = new_transform
|
||||
|
||||
|
||||
|
||||
@rpc("any_peer", "call_local", "reliable")
|
||||
func server_update_visibility(ghost_visible: bool, station_visible: bool) -> void:
|
||||
SweetLogger.debug("server_update_visibility", [], "station_movement.gd", "server_update_visibility")
|
||||
move_ghost.visible = ghost_visible
|
||||
station.visible = station_visible
|
||||
|
||||
|
||||
@rpc("any_peer", "call_local", "unreliable")
|
||||
func server_update_move_ghost_transform(new_transform: Transform3D, new_color: Color = Color.YELLOW) -> void:
|
||||
SweetLogger.debug("server_update_move_ghost_transform", [], "station_movement.gd", "server_update_move_ghost_transform")
|
||||
move_ghost.global_transform = new_transform
|
||||
_set_ghost_color(new_color)
|
||||
|
||||
+23
-23
@@ -47,7 +47,7 @@ var _players_count: int = 0
|
||||
|
||||
|
||||
func place_order() -> void:
|
||||
print("Table place_order()")
|
||||
SweetLogger.debug("place_order()", [], "table.gd", "place_order")
|
||||
var new_orders: Array[String] = _unsatisfied_orders.duplicate()
|
||||
# for _i in range(0, randi_range(1, 2)):
|
||||
# new_orders.append(GameManager.get_random_meal())
|
||||
@@ -59,7 +59,7 @@ func place_order() -> void:
|
||||
|
||||
|
||||
func absorb_items():
|
||||
print("Table: absorb_items()")
|
||||
SweetLogger.debug("absorb_items()", [], "table.gd", "absorb_items")
|
||||
for snap_zone_node in snap_zones:
|
||||
var held_object = snap_zone_node.picked_up_object
|
||||
if not held_object:
|
||||
@@ -69,7 +69,7 @@ func absorb_items():
|
||||
|
||||
|
||||
func satisfyAllOrders() -> void:
|
||||
print("Table: satisfyAllOrders()")
|
||||
SweetLogger.debug("satisfyAllOrders()", [], "table.gd", "satisfyAllOrders")
|
||||
_unsatisfied_orders.clear()
|
||||
_original_orders.clear()
|
||||
clearAllFood()
|
||||
@@ -77,7 +77,7 @@ func satisfyAllOrders() -> void:
|
||||
|
||||
|
||||
func clearAllFood() -> void:
|
||||
print("Table: clearAllFood()")
|
||||
SweetLogger.debug("clearAllFood()", [], "table.gd", "clearAllFood")
|
||||
for zone in snap_zones:
|
||||
var held_object = zone.picked_up_object
|
||||
if not held_object:
|
||||
@@ -98,7 +98,7 @@ func clearAllFood() -> void:
|
||||
# Group called from Queue when trying to assign customers to tables
|
||||
func try_consume_customer() -> bool:
|
||||
if _state == TableState.EMPTY:
|
||||
print("Table try_consume_customer, consumed a customer")
|
||||
SweetLogger.debug("try_consume_customer, consumed a customer", [], "table.gd", "try_consume_customer")
|
||||
_state_end(TableState.EMPTY)
|
||||
return true
|
||||
return false
|
||||
@@ -137,14 +137,14 @@ func _ready() -> void:
|
||||
|
||||
|
||||
func _on_object_picked_up(_item) -> void:
|
||||
print("Table: object picked up: ", _item)
|
||||
SweetLogger.debug("object picked up: {0}", [_item], "table.gd", "_on_object_picked_up")
|
||||
if _state == TableState.EATING:
|
||||
return
|
||||
_absorb_item_if_correct(_item)
|
||||
|
||||
|
||||
func _on_object_dropped(_item) -> void:
|
||||
print("Table: object dropped, item: ", _item)
|
||||
SweetLogger.debug("object dropped, item: {0}", [_item], "table.gd", "_on_object_dropped")
|
||||
# If then player picks up a food_item (side) the table has already registerd, unregister
|
||||
var food_item: FoodItem = Helper.find_food_item(_item)
|
||||
if food_item and food_item.type == FoodItem.Type.SIDE:
|
||||
@@ -161,12 +161,12 @@ func _on_object_dropped(_item) -> void:
|
||||
# There is no on_stay signal, we have to track player with bool
|
||||
func _on_player_enter(_body):
|
||||
_players_count += 1
|
||||
print("Table _on_player_enter() pleryers_count: ", _players_count)
|
||||
SweetLogger.debug("_on_player_enter() players_count: {0}", [_players_count], "table.gd", "_on_player_enter")
|
||||
|
||||
|
||||
func _on_player_exit(_body):
|
||||
_players_count -= 1
|
||||
print("Table _on_player_exit() pleryers_count: ", _players_count)
|
||||
SweetLogger.debug("_on_player_exit() players_count: {0}", [_players_count], "table.gd", "_on_player_exit")
|
||||
|
||||
|
||||
func _place_order_if_player():
|
||||
@@ -183,20 +183,20 @@ func _place_order_if_player():
|
||||
|
||||
func _get_plate_controller_from_item(_item: Node) -> PlateController:
|
||||
if not _item:
|
||||
print("_item is null")
|
||||
SweetLogger.debug("_item is null", [], "table.gd", "_get_plate_controller_from_item")
|
||||
return null
|
||||
|
||||
for child in _item.get_children():
|
||||
if child is PlateController:
|
||||
print("found child")
|
||||
SweetLogger.debug("found child", [], "table.gd", "_get_plate_controller_from_item")
|
||||
return child
|
||||
|
||||
print("no match")
|
||||
SweetLogger.debug("no match", [], "table.gd", "_get_plate_controller_from_item")
|
||||
return null
|
||||
|
||||
|
||||
func _absorb_item_if_correct(_item: Node) -> void:
|
||||
print("Table _absorb_item_if_correct, item: ", _item)
|
||||
SweetLogger.debug("_absorb_item_if_correct, item: {0}", [_item], "table.gd", "_absorb_item_if_correct")
|
||||
if not _item:
|
||||
return
|
||||
if not (_state == TableState.WAITING_PRIMARY or _state == TableState.WAITING_FRIEND):
|
||||
@@ -204,14 +204,14 @@ func _absorb_item_if_correct(_item: Node) -> void:
|
||||
|
||||
# Plate: Get plate controller in child of _item (hopefully a plate XRpickable)
|
||||
var plate_controller = _get_plate_controller_from_item(_item)
|
||||
print("Table _absorb_item_if_correct plate_controller ref: ", plate_controller)
|
||||
SweetLogger.debug("_absorb_item_if_correct plate_controller ref: {0}", [plate_controller], "table.gd", "_absorb_item_if_correct")
|
||||
_item.print_tree_pretty()
|
||||
|
||||
if plate_controller:
|
||||
# Absorm items from the plate we want
|
||||
for food_item: FoodItem in plate_controller.container.contained_items: # TOOD: handle registering the meal again when a side is added to the plate
|
||||
if food_item.id in _unsatisfied_orders and not food_item.is_absorbed:
|
||||
print("Table: _absorb_item_if_correct held a plate with FoodItem that is in unsatisfied orders, removing it")
|
||||
SweetLogger.debug("_absorb_item_if_correct held a plate with FoodItem that is in unsatisfied orders, removing it", [], "table.gd", "_absorb_item_if_correct")
|
||||
(plate_controller.get_parent() as XRToolsPickable).get_picked_up_by().enabled = false # Lock meal that is deliverd
|
||||
_unsatisfied_orders.erase(food_item.id)
|
||||
food_item.is_absorbed = true
|
||||
@@ -221,17 +221,17 @@ func _absorb_item_if_correct(_item: Node) -> void:
|
||||
# Side pickable item, no container
|
||||
var food_item: FoodItem = Helper.find_food_item(_item)
|
||||
if food_item and food_item.type == FoodItem.Type.SIDE:
|
||||
print("Table: _absorb_item_if_correct held a side that is in unsatisfied orders, removing it")
|
||||
SweetLogger.debug("_absorb_item_if_correct held a side that is in unsatisfied orders, removing it", [], "table.gd", "_absorb_item_if_correct")
|
||||
# Do not lock snap zone here. Problem if table want many meals, but to many sides have filled up slots, so can't place plates.
|
||||
_unsatisfied_orders.erase(food_item.id)
|
||||
_update_state_from_orders()
|
||||
return
|
||||
|
||||
print("Table: absorb_item_if_correct() held object is not a Plate or Side")
|
||||
SweetLogger.debug("absorb_item_if_correct() held object is not a Plate or Side", [], "table.gd", "_absorb_item_if_correct")
|
||||
|
||||
|
||||
func _update_state_from_orders():
|
||||
print("Table _update_state_from_orders: unsatisfied_orders: ", _unsatisfied_orders)
|
||||
SweetLogger.debug("_update_state_from_orders: unsatisfied_orders: {0}", [_unsatisfied_orders], "table.gd", "_update_state_from_orders")
|
||||
if _unsatisfied_orders.size() > 0 and _state != TableState.EATING:
|
||||
_set_state(TableState.WAITING_FRIEND)
|
||||
|
||||
@@ -250,11 +250,11 @@ func _collect_money_from_food():
|
||||
var food_item: FoodItem = Helper.find_food_item(held_object)
|
||||
if plate:
|
||||
for fi: FoodItem in plate.get_food_items():
|
||||
GameManager.money += fi.sell_value
|
||||
GameManager.set_money(GameManager.money + fi.sell_value)
|
||||
elif food_item:
|
||||
GameManager.money += food_item.sell_value
|
||||
GameManager.set_money(GameManager.money + food_item.sell_value)
|
||||
|
||||
print("Table _collect_money_from_food(), money: ", GameManager.money)
|
||||
SweetLogger.debug("_collect_money_from_food(), money: {0}", [GameManager.money], "table.gd", "_collect_money_from_food")
|
||||
|
||||
|
||||
func _set_snap_zones_enabled(value: bool) -> void:
|
||||
@@ -265,7 +265,7 @@ func _set_snap_zones_enabled(value: bool) -> void:
|
||||
## Server-only state transition: sets the new state's timer and assigns
|
||||
## _state (whose setter refreshes the display on every peer).
|
||||
func _set_state(newState: TableState) -> void:
|
||||
print("Table State START: ", TableState.keys()[newState])
|
||||
SweetLogger.debug("State START: {0}", [TableState.keys()[newState]], "table.gd", "_set_state")
|
||||
|
||||
match newState:
|
||||
TableState.IDLE:
|
||||
@@ -307,7 +307,7 @@ func _set_state(newState: TableState) -> void:
|
||||
|
||||
# When state timer is finished, do this stuff before moving to next state
|
||||
func _state_end(oldState: TableState):
|
||||
print("Table State END : ", TableState.keys()[oldState])
|
||||
SweetLogger.debug("State END: {0}", [TableState.keys()[oldState]], "table.gd", "_state_end")
|
||||
match oldState:
|
||||
TableState.EMPTY:
|
||||
customers.visible = true
|
||||
|
||||
+24
-14
@@ -7,6 +7,26 @@
|
||||
[ext_resource type="AudioStream" uid="uid://daiv8ubwdbidf" path="res://sounds/220195__gameaudio__click-wooden-1.wav" id="3_0s6ir"]
|
||||
[ext_resource type="PackedScene" uid="uid://bxbocxdaayvwx" path="res://UI/progress_bar.tscn" id="3_kjf1i"]
|
||||
|
||||
[sub_resource type="SceneReplicationConfig" id="SceneReplicationConfig_np_table"]
|
||||
properties/0/path = NodePath(".:_state")
|
||||
properties/0/spawn = false
|
||||
properties/0/replication_mode = 1
|
||||
properties/1/path = NodePath(".:_state_time")
|
||||
properties/1/spawn = false
|
||||
properties/1/replication_mode = 1
|
||||
properties/2/path = NodePath(".:_unsatisfied_orders")
|
||||
properties/2/spawn = false
|
||||
properties/2/replication_mode = 1
|
||||
properties/3/path = NodePath(".:position")
|
||||
properties/3/spawn = false
|
||||
properties/3/replication_mode = 1
|
||||
properties/4/path = NodePath(".:rotation")
|
||||
properties/4/spawn = false
|
||||
properties/4/replication_mode = 1
|
||||
properties/5/path = NodePath(".:visible")
|
||||
properties/5/spawn = false
|
||||
properties/5/replication_mode = 1
|
||||
|
||||
[sub_resource type="BoxShape3D" id="BoxShape3D_24d3s"]
|
||||
size = Vector3(0.7983472, 0.060000002, 0.59873295)
|
||||
|
||||
@@ -16,17 +36,6 @@ radius = 0.6
|
||||
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_24d3s"]
|
||||
albedo_color = Color(0.31, 0.21576, 0.1333, 1)
|
||||
|
||||
[sub_resource type="SceneReplicationConfig" id="SceneReplicationConfig_np_table"]
|
||||
properties/0/path = NodePath(".:_state")
|
||||
properties/0/spawn = true
|
||||
properties/0/replication_mode = 1
|
||||
properties/1/path = NodePath(".:_state_time")
|
||||
properties/1/spawn = true
|
||||
properties/1/replication_mode = 1
|
||||
properties/2/path = NodePath(".:_unsatisfied_orders")
|
||||
properties/2/spawn = true
|
||||
properties/2/replication_mode = 1
|
||||
|
||||
[sub_resource type="BoxShape3D" id="BoxShape3D_vlqg6"]
|
||||
size = Vector3(2.1, 0.5, 2.1)
|
||||
|
||||
@@ -35,6 +44,10 @@ size = Vector3(2.1, 0.5, 2.1)
|
||||
[node name="StationMovement" parent="." unique_id=946873975 node_paths=PackedStringArray("station") instance=ExtResource("1_5mi7y")]
|
||||
station = NodePath("../Table")
|
||||
|
||||
[node name="MultiplayerSyncronizer" type="MultiplayerSynchronizer" parent="." unique_id=2000411505]
|
||||
root_path = NodePath("../Table")
|
||||
replication_config = SubResource("SceneReplicationConfig_np_table")
|
||||
|
||||
[node name="Table" type="StaticBody3D" parent="." unique_id=1863572470 groups=["station", "table"]]
|
||||
script = ExtResource("1_2vcpj")
|
||||
money_sound = ExtResource("2_jslhm")
|
||||
@@ -154,9 +167,6 @@ pixel_size = 0.003
|
||||
billboard = 2
|
||||
text = "20.1s"
|
||||
|
||||
[node name="Sync" type="MultiplayerSynchronizer" parent="Table" unique_id=2000411505]
|
||||
replication_config = SubResource("SceneReplicationConfig_np_table")
|
||||
|
||||
[node name="ProgressBar3D" parent="Table" unique_id=654673176 instance=ExtResource("3_kjf1i")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.8692299, 0)
|
||||
y_billboard = true
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[gd_resource type="StandardMaterial3D" format=3 uid="uid://cmia50cfqxxo4"]
|
||||
|
||||
[ext_resource type="Texture2D" uid="uid://eqp04wybmg" path="res://Textures/devTex.svg" id="1_3jxsn"]
|
||||
[ext_resource type="Texture2D" uid="uid://eqp04wybmg" path="res://textures/devTex.svg" id="1_3jxsn"]
|
||||
|
||||
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_0gbf8"]
|
||||
transparency = 1
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[gd_resource type="Sky" format=3 uid="uid://c1abtpwhdm2d5"]
|
||||
|
||||
[ext_resource type="Texture2D" uid="uid://ci0hjoabnf8nu" path="res://Textures/sky/NightSkyHDRI009_16K_HDR.exr" id="acg_mft3ic9d"]
|
||||
[ext_resource type="Texture2D" uid="uid://ci0hjoabnf8nu" path="res://textures/sky/NightSkyHDRI009_16K_HDR.exr" id="acg_mft3ic9d"]
|
||||
|
||||
[sub_resource type="PanoramaSkyMaterial" id="acg_025sfqr4"]
|
||||
panorama = ExtResource("acg_mft3ic9d")
|
||||
|
||||
@@ -48,7 +48,7 @@ func _ready() -> void:
|
||||
## --server / --join <ip> on the command line skip straight to the multiplayer
|
||||
## scene, same as the previously headless-tested main.tscn flow.
|
||||
func _bypass_menu_for_cmdline() -> bool:
|
||||
var args := OS.get_cmdline_user_args()
|
||||
var args := OS.get_cmdline_args()
|
||||
if args.has("--server"):
|
||||
NetworkManager.request_host()
|
||||
get_tree().change_scene_to_file.call_deferred(MULTIPLAYER_SCENE)
|
||||
|
||||
@@ -17,12 +17,13 @@ func _ready() -> void:
|
||||
|
||||
|
||||
func _on_button_pressed() -> void:
|
||||
print("ShopStationButton buy ", station_name)
|
||||
SweetLogger.debug("buy {0}", [station_name], "shop_station_button.gd", "_on_button_pressed")
|
||||
_buy_station()
|
||||
|
||||
|
||||
func _buy_station() -> void:
|
||||
GameManager.money -= cost
|
||||
SweetLogger.debug("_buy_station: cost={0} current money={1}", [cost, GameManager.money], "shop_station_button.gd", "_buy_station")
|
||||
GameManager.set_money(GameManager.money - cost)
|
||||
var transform = Helper.get_snapped_transform(XRHelpers.get_xr_origin(self).get_node_or_null("PlayerBody"))
|
||||
var forward: Vector3 = -transform.basis.z.normalized()
|
||||
transform.origin += (forward * 0.6)
|
||||
@@ -33,7 +34,7 @@ func _buy_station() -> void:
|
||||
|
||||
Signals.station_bought.emit(instance)
|
||||
|
||||
@rpc("reliable")
|
||||
@rpc("any_peer", "call_remote", "reliable")
|
||||
func _ask_server_to_spawn(station_scene_path, transform):
|
||||
NetworkManager.spawn_item(station_scene_path, transform)
|
||||
|
||||
|
||||
+10
-7
@@ -32,8 +32,10 @@ func _process(_delta: float) -> void:
|
||||
|
||||
func toggle_shop():
|
||||
if GameManager.game_state == GameManager.GameState.BUILDING:
|
||||
print("Shop UI toggle shop")
|
||||
SweetLogger.debug("toggle shop", [], "shop_ui.gd", "toggle_shop")
|
||||
enabled = !enabled
|
||||
SweetLogger.debug("_process: money={0} label text={1}", [GameManager.money, money_label.text], "shop_ui.gd", "toggle_shop")
|
||||
|
||||
|
||||
|
||||
func _set_enabled(value: bool) -> void:
|
||||
@@ -52,15 +54,14 @@ func _set_poke_enabled_for_controller(controller_node: XRController3D, value: bo
|
||||
|
||||
var poke_node = Helper.find_first_child_of_type(controller_node, XRToolsPoke)
|
||||
if poke_node:
|
||||
print("Shop UI _set_poke_enabled_for_controller: ", poke_node.get_path(), " poke enabled: ", value)
|
||||
SweetLogger.debug("_set_poke_enabled_for_controller: {0} poke enabled: {1}", [poke_node.get_path(), value], "shop_ui.gd", "_set_poke_enabled_for_controller")
|
||||
poke_node.enabled = value
|
||||
poke_node.visible = value
|
||||
else:
|
||||
print("Shop UI _set_poke_enabled_for_controller: ", controller_node.name, " poke not found")
|
||||
SweetLogger.debug("_set_poke_enabled_for_controller: {0} poke not found", [controller_node.name], "shop_ui.gd", "_set_poke_enabled_for_controller")
|
||||
|
||||
# For some reason, this is called every frame the button is down. So we need our own timer.
|
||||
func _on_controller_button_pressed(button_name: String) -> void:
|
||||
print("Shop _on_controller_button_pressed, button: ", button_name)
|
||||
var now := Time.get_ticks_msec() / 1000.0
|
||||
if now - _last_toggle_time < INPUT_TOGGLE_COOLDOWN:
|
||||
return
|
||||
@@ -76,9 +77,11 @@ func _on_other_controller_button_pressed(button_name: String) -> void:
|
||||
enabled = false
|
||||
|
||||
|
||||
func _on_station_bought(instance) -> void:
|
||||
func _on_station_bought(_instance) -> void:
|
||||
enabled = false
|
||||
|
||||
money_label.text = str(GameManager.money) + "$"
|
||||
SweetLogger.debug("_on_station_bought: new money: {0}", [GameManager.money], "shop_ui.gd", "_on_station_bought")
|
||||
|
||||
|
||||
func detect_hand_from_xr_ancestor() -> void:
|
||||
controller = XRHelpers.get_xr_controller(self)
|
||||
@@ -93,4 +96,4 @@ func detect_hand_from_xr_ancestor() -> void:
|
||||
other_controller = right_controller
|
||||
elif controller == right_controller:
|
||||
other_controller = left_controller
|
||||
print("Shop UI detected hand: ", controller.get_tracker_hand())
|
||||
SweetLogger.debug("detected hand: {0}", [controller.get_tracker_hand()], "shop_ui.gd", "detect_hand_from_xr_ancestor")
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
[gd_resource type="ShaderMaterial" load_steps=7 format=3 uid="uid://dyuaw57o8y3i"]
|
||||
[gd_resource type="ShaderMaterial" format=3 uid="uid://dyuaw57o8y3i"]
|
||||
|
||||
[sub_resource type="VisualShaderNodeColorParameter" id="VisualShaderNodeColorParameter_nl6jr"]
|
||||
parameter_name = "Color"
|
||||
@@ -16,42 +16,6 @@ constant = 0.1
|
||||
operator = 2
|
||||
|
||||
[sub_resource type="VisualShader" id="VisualShader_wb0u4"]
|
||||
code = "shader_type spatial;
|
||||
render_mode blend_mix, depth_draw_opaque, cull_back, diffuse_lambert, specular_schlick_ggx;
|
||||
|
||||
uniform vec4 Color : source_color;
|
||||
|
||||
|
||||
|
||||
void fragment() {
|
||||
// ColorParameter:2
|
||||
vec4 n_out2p0 = Color;
|
||||
|
||||
|
||||
// FloatConstant:4
|
||||
float n_out4p0 = 0.100000;
|
||||
|
||||
|
||||
// VectorOp:3
|
||||
vec3 n_out3p0 = vec3(n_out2p0.xyz) * vec3(n_out4p0);
|
||||
|
||||
|
||||
// Fresnel:5
|
||||
float n_in5p3 = 1.00000;
|
||||
float n_out5p0 = pow(1.0 - clamp(dot(NORMAL, VIEW), 0.0, 1.0), n_in5p3);
|
||||
|
||||
|
||||
// VectorOp:6
|
||||
vec3 n_out6p0 = vec3(n_out2p0.xyz) * vec3(n_out5p0);
|
||||
|
||||
|
||||
// Output:0
|
||||
ALBEDO = n_out3p0;
|
||||
EMISSION = n_out6p0;
|
||||
|
||||
|
||||
}
|
||||
"
|
||||
nodes/fragment/0/position = Vector2(660, 60)
|
||||
nodes/fragment/2/node = SubResource("VisualShaderNodeColorParameter_nl6jr")
|
||||
nodes/fragment/2/position = Vector2(40, 40)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
[gd_resource type="VisualShader" load_steps=28 format=3 uid="uid://c6okm2ay0fkjf"]
|
||||
[gd_resource type="VisualShader" format=3 uid="uid://c6okm2ay0fkjf"]
|
||||
|
||||
[sub_resource type="VisualShaderNodeFloatOp" id="1"]
|
||||
output_port_for_preview = 0
|
||||
@@ -101,159 +101,6 @@ output_port_for_preview = 0
|
||||
function = 12
|
||||
|
||||
[resource]
|
||||
code = "shader_type spatial;
|
||||
render_mode blend_mix, depth_draw_opaque, cull_back, diffuse_lambert, specular_schlick_ggx, unshaded;
|
||||
|
||||
uniform vec4 albedo : source_color;
|
||||
uniform float value;
|
||||
uniform float fade;
|
||||
uniform float radius;
|
||||
uniform float width;
|
||||
|
||||
|
||||
|
||||
void fragment() {
|
||||
// ColorParameter:2
|
||||
vec4 n_out2p0 = albedo;
|
||||
|
||||
|
||||
// Input:3
|
||||
vec2 n_out3p0 = UV;
|
||||
|
||||
|
||||
// VectorOp:4
|
||||
vec3 n_in4p1 = vec3(2.00000, 2.00000, 0.00000);
|
||||
vec3 n_out4p0 = vec3(n_out3p0, 0.0) * n_in4p1;
|
||||
|
||||
|
||||
// VectorOp:5
|
||||
vec3 n_in5p1 = vec3(-1.00000, -1.00000, 0.00000);
|
||||
vec3 n_out5p0 = n_out4p0 + n_in5p1;
|
||||
|
||||
|
||||
// VectorFunc:17
|
||||
vec3 n_out17p0 = normalize(n_out5p0);
|
||||
|
||||
|
||||
// VectorOp:19
|
||||
vec3 n_in19p1 = vec3(0.00000, -1.00000, 0.00000);
|
||||
vec3 n_out19p0 = cross(n_out17p0, n_in19p1);
|
||||
|
||||
|
||||
// VectorDecompose:20
|
||||
float n_out20p0 = n_out19p0.x;
|
||||
float n_out20p1 = n_out19p0.y;
|
||||
float n_out20p2 = n_out19p0.z;
|
||||
|
||||
|
||||
// DotProduct:18
|
||||
vec3 n_in18p1 = vec3(0.00000, -1.00000, 0.00000);
|
||||
float n_out18p0 = dot(n_out17p0, n_in18p1);
|
||||
|
||||
|
||||
// FloatFunc:24
|
||||
float n_out24p0 = acos(n_out18p0);
|
||||
|
||||
|
||||
// FloatOp:23
|
||||
float n_in23p0 = 6.28319;
|
||||
float n_out23p0 = n_in23p0 - n_out24p0;
|
||||
|
||||
|
||||
vec3 n_out22p0;
|
||||
// If:22
|
||||
float n_in22p1 = 0.00000;
|
||||
float n_in22p2 = 0.00001;
|
||||
if(abs(n_out20p2 - n_in22p1) < n_in22p2)
|
||||
{
|
||||
n_out22p0 = vec3(n_out24p0);
|
||||
}
|
||||
else if(n_out20p2 < n_in22p1)
|
||||
{
|
||||
n_out22p0 = vec3(n_out24p0);
|
||||
}
|
||||
else
|
||||
{
|
||||
n_out22p0 = vec3(n_out23p0);
|
||||
}
|
||||
|
||||
|
||||
// FloatOp:25
|
||||
float n_in25p1 = 6.28319;
|
||||
float n_out25p0 = n_out22p0.x / n_in25p1;
|
||||
|
||||
|
||||
// FloatParameter:26
|
||||
float n_out26p0 = value;
|
||||
|
||||
|
||||
// FloatOp:27
|
||||
float n_out27p0 = n_out25p0 - n_out26p0;
|
||||
|
||||
|
||||
// FloatParameter:14
|
||||
float n_out14p0 = fade;
|
||||
|
||||
|
||||
// FloatOp:30
|
||||
float n_in30p1 = 6.28319;
|
||||
float n_out30p0 = n_out14p0 / n_in30p1;
|
||||
|
||||
|
||||
// FloatOp:28
|
||||
float n_out28p0 = n_out27p0 / n_out30p0;
|
||||
|
||||
|
||||
// VectorLen:6
|
||||
float n_out6p0 = length(n_out5p0);
|
||||
|
||||
|
||||
// FloatParameter:8
|
||||
float n_out8p0 = radius;
|
||||
|
||||
|
||||
// FloatOp:7
|
||||
float n_out7p0 = n_out6p0 - n_out8p0;
|
||||
|
||||
|
||||
// FloatFunc:9
|
||||
float n_out9p0 = abs(n_out7p0);
|
||||
|
||||
|
||||
// FloatParameter:11
|
||||
float n_out11p0 = width;
|
||||
|
||||
|
||||
// FloatOp:15
|
||||
float n_in15p1 = 2.00000;
|
||||
float n_out15p0 = n_out11p0 / n_in15p1;
|
||||
|
||||
|
||||
// FloatOp:13
|
||||
float n_out13p0 = n_out9p0 - n_out15p0;
|
||||
|
||||
|
||||
// FloatOp:10
|
||||
float n_out10p0 = n_out13p0 / n_out14p0;
|
||||
|
||||
|
||||
// FloatOp:29
|
||||
float n_out29p0 = max(n_out28p0, n_out10p0);
|
||||
|
||||
|
||||
// FloatOp:12
|
||||
float n_in12p0 = 1.00000;
|
||||
float n_out12p0 = n_in12p0 - n_out29p0;
|
||||
|
||||
|
||||
// Output:0
|
||||
ALBEDO = vec3(n_out2p0.xyz);
|
||||
ALPHA = n_out12p0;
|
||||
|
||||
|
||||
}
|
||||
"
|
||||
graph_offset = Vector2(652.664, 119.317)
|
||||
flags/unshaded = true
|
||||
nodes/fragment/0/position = Vector2(1800, -40)
|
||||
nodes/fragment/2/node = SubResource("3")
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
[gd_resource type="VisualShader" load_steps=16 format=3 uid="uid://4i0pwdtfmtsv"]
|
||||
[gd_resource type="VisualShader" format=3 uid="uid://4i0pwdtfmtsv"]
|
||||
|
||||
[sub_resource type="VisualShaderNodeCompare" id="5"]
|
||||
output_port_for_preview = 0
|
||||
@@ -62,95 +62,6 @@ function = 2
|
||||
condition = 1
|
||||
|
||||
[resource]
|
||||
code = "shader_type spatial;
|
||||
render_mode blend_mix, depth_draw_opaque, cull_back, diffuse_lambert, specular_schlick_ggx, unshaded;
|
||||
|
||||
uniform vec4 bar_color : source_color;
|
||||
uniform sampler2D bar_texture : source_color;
|
||||
uniform vec3 cutout = vec3(4.850000, 0.330000, 0.000000);
|
||||
uniform float progress;
|
||||
|
||||
|
||||
|
||||
void fragment() {
|
||||
// ColorParameter:15
|
||||
vec4 n_out15p0 = bar_color;
|
||||
|
||||
|
||||
vec4 n_out19p0;
|
||||
// Texture2D:19
|
||||
n_out19p0 = texture(bar_texture, UV);
|
||||
float n_out19p4 = n_out19p0.a;
|
||||
|
||||
|
||||
// VectorOp:17
|
||||
vec3 n_out17p0 = vec3(n_out15p0.xyz) * vec3(n_out19p0.xyz);
|
||||
|
||||
|
||||
// Input:3
|
||||
vec2 n_out3p0 = UV;
|
||||
|
||||
|
||||
// VectorOp:4
|
||||
vec3 n_in4p1 = vec3(10.00000, 1.00000, 0.00000);
|
||||
vec3 n_out4p0 = vec3(n_out3p0, 0.0) * n_in4p1;
|
||||
|
||||
|
||||
// VectorOp:5
|
||||
vec3 n_in5p1 = vec3(5.00000, 0.50000, 0.00000);
|
||||
vec3 n_out5p0 = n_out4p0 - n_in5p1;
|
||||
|
||||
|
||||
// VectorFunc:6
|
||||
vec3 n_out6p0 = abs(n_out5p0);
|
||||
|
||||
|
||||
// Vector3Parameter:20
|
||||
vec3 n_out20p0 = cutout;
|
||||
|
||||
|
||||
bool n_out8p0;
|
||||
// Compare:8
|
||||
{
|
||||
bvec2 _bv = greaterThan(vec2(n_out6p0.xy), vec2(n_out20p0.xy));
|
||||
n_out8p0 = any(_bv);
|
||||
}
|
||||
|
||||
|
||||
// FloatParameter:12
|
||||
float n_out12p0 = progress;
|
||||
|
||||
|
||||
// VectorCompose:13
|
||||
float n_in13p1 = 0.00000;
|
||||
float n_in13p2 = 0.00000;
|
||||
vec3 n_out13p0 = vec3(n_out12p0, n_in13p1, n_in13p2);
|
||||
|
||||
|
||||
bool n_out11p0;
|
||||
// Compare:11
|
||||
{
|
||||
bvec2 _bv = lessThan(n_out3p0, vec2(n_out13p0.xy));
|
||||
n_out11p0 = any(_bv);
|
||||
}
|
||||
|
||||
|
||||
// FloatOp:14
|
||||
float n_out14p0 = max((n_out8p0 ? 1.0 : 0.0), (n_out11p0 ? 1.0 : 0.0));
|
||||
|
||||
|
||||
// FloatOp:18
|
||||
float n_out18p0 = n_out19p4 * n_out14p0;
|
||||
|
||||
|
||||
// Output:0
|
||||
ALBEDO = n_out17p0;
|
||||
ALPHA = n_out18p0;
|
||||
|
||||
|
||||
}
|
||||
"
|
||||
graph_offset = Vector2(-744.269, 307.118)
|
||||
flags/unshaded = true
|
||||
nodes/fragment/0/position = Vector2(1220, 440)
|
||||
nodes/fragment/3/node = SubResource("10")
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2026 sweetpea
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -0,0 +1,105 @@
|
||||
## hey - sweet logger you got there!
|
||||
---
|
||||
|
||||
A Godot 4 addon that makes reading logs and debugging sane when you run multiple game instances at once.
|
||||
|
||||
It's meant as a drop-in/stand-in for `print()`: same habit of sprinkling logs through your systems, but every line carries more context - which peer printed it, what kind of log it is, which script and function it came from. That makes it much easier to follow what each client (and the server) is doing when several instances share one console.
|
||||
|
||||
When you're testing multiplayer locally (host + clients in separate run instances), the editor console fills with interleaved output from every peer. Sweet Logger formats each line the same way so you can tell at a glance **what kind of log it is**, **which peer it came from**, **when it happened**, and **which script/function** produced it.
|
||||
|
||||
---
|
||||
|
||||
## Features
|
||||
|
||||
- **Peer-aware labels** - tags each line as `SERVER`, a client peer ID, or `DISCONNECTED`
|
||||
- **Color-coded peers** - consistent colors per peer so interleaved console output is easy to scan
|
||||
- **Log levels** - `log`, `info`, `warning`, `error`, `debug` with distinct colors
|
||||
- **Script context** - optional script and function name columns
|
||||
- **Local timestamps** - `mm:ss:ms` by default (optional hours)
|
||||
- **Rich console output** - uses `print_rich` with aligned columns
|
||||
|
||||
---
|
||||
|
||||
## Installation
|
||||
|
||||
### From the Godot Asset Library
|
||||
|
||||
1. In Godot, open the **AssetLib** tab.
|
||||
2. Search for **Sweet Logger** and download it.
|
||||
3. Open **Project → Project Settings → Plugins** and enable **Sweet Logger**.
|
||||
4. The plugin registers a `SweetLogger` autoload automatically.
|
||||
|
||||
### Manual
|
||||
|
||||
1. Copy the `addons/sweet-logger` folder into your project's `addons/` directory.
|
||||
2. In Godot, open **Project → Project Settings → Plugins** and enable **Sweet Logger**.
|
||||
3. The plugin registers a `SweetLogger` autoload automatically.
|
||||
|
||||
---
|
||||
|
||||
## Usage
|
||||
|
||||
Call the autoload from anywhere:
|
||||
|
||||
```gdscript
|
||||
SweetLogger.info("Player joined", [], "lobby.gd", "on_peer_connected")
|
||||
SweetLogger.warning("High latency: {0}ms", [rtt], "net.gd", "_process")
|
||||
SweetLogger.error("RPC failed", [], "sync.gd", "apply_state")
|
||||
SweetLogger.debug("Tick {0}", [tick], "game.gd", "_physics_process")
|
||||
SweetLogger.log("Hello from peer")
|
||||
```
|
||||
|
||||
### Message formatting
|
||||
|
||||
Pass optional args and use `{0}`, `{1}`, … placeholders:
|
||||
|
||||
```gdscript
|
||||
SweetLogger.info("Spawned {0} at {1}", [entity_name, position], "spawner.gd", "spawn")
|
||||
```
|
||||
|
||||
### API
|
||||
|
||||
| Method | Level |
|
||||
| --------------------------------------------------------------------- | ------- |
|
||||
| `SweetLogger.log(message, args=[], script_name="", function_name="")` | General |
|
||||
| `SweetLogger.info(...)` | Info |
|
||||
| `SweetLogger.warning(...)` | Warning |
|
||||
| `SweetLogger.error(...)` | Error |
|
||||
| `SweetLogger.debug(...)` | Debug |
|
||||
|
||||
|
||||
All methods share the same signature: message, optional format args, optional script name, optional function name.
|
||||
|
||||
## Configuration
|
||||
|
||||
On the `SweetLogger` autoload (or in the inspector when selected):
|
||||
|
||||
|
||||
| Export | Default | Description |
|
||||
| ---------------------- | ------- | --------------------------------------- |
|
||||
| `SHOW_SCRIPT_NAME` | `true` | Include the script name column |
|
||||
| `SHOW_FUNCTION_NAME` | `true` | Include the function name column |
|
||||
| `SHOW_TIMESTAMP_HOURS` | `false` | Use `hh:mm:ss:ms` instead of `mm:ss:ms` |
|
||||
|
||||
## Log line layout
|
||||
|
||||
Each line is roughly:
|
||||
|
||||
```
|
||||
[LEVEL][timestamp][PEER][script::function] message
|
||||
```
|
||||
|
||||
- **LEVEL** - color by type (info blue, warning yellow, error red, etc.)
|
||||
- **timestamp** - local time for correlating events across instances
|
||||
- **PEER** - `SERVER`, numeric client ID, or `DISCONNECTED`, each with a stable color
|
||||
- **script::function** - where the log was emitted (when you pass those args)
|
||||
|
||||
---
|
||||
|
||||
## Why this exists
|
||||
|
||||
Godot's "Run Multiple Instances" is great for testing multiplayer games on one machine, but plain `print()` output from every peer lands in one console with no clear ownership. Sweet Logger keeps a fixed column layout and peer coloring so you can follow one client's story (or the server's) without losing the others.
|
||||
|
||||
## License
|
||||
|
||||
MIT - see [LICENSE](addons/sweet-logger/LICENSE).
|
||||
@@ -0,0 +1,7 @@
|
||||
[plugin]
|
||||
|
||||
name="Sweet Logger"
|
||||
description="Rich console logging with peer-aware prefixes. Registers the SweetLogger autoload."
|
||||
author="sweetpea"
|
||||
version="1.0.0"
|
||||
script="plugin.gd"
|
||||
@@ -0,0 +1,13 @@
|
||||
@tool
|
||||
extends EditorPlugin
|
||||
|
||||
const AUTOLOAD_NAME := "SweetLogger"
|
||||
const AUTOLOAD_PATH := "res://addons/sweet-logger/sweet_logger.gd"
|
||||
|
||||
func _enter_tree() -> void:
|
||||
var key := "autoload/%s" % AUTOLOAD_NAME
|
||||
if not ProjectSettings.has_setting(key):
|
||||
add_autoload_singleton(AUTOLOAD_NAME, AUTOLOAD_PATH)
|
||||
|
||||
func _exit_tree() -> void:
|
||||
remove_autoload_singleton(AUTOLOAD_NAME)
|
||||
@@ -0,0 +1 @@
|
||||
uid://cm16x8s6cox4w
|
||||
@@ -0,0 +1,289 @@
|
||||
extends Node
|
||||
|
||||
## Global Logger singleton for consistent logging across the game.
|
||||
## All logs are prefixed with [peer_id]: to identify which instance is logging.
|
||||
## Uses print_rich with colorized backgrounds for log type, local time, peer IDs, and script context.
|
||||
|
||||
# COLORS
|
||||
#===================================================================================#
|
||||
## Log type configuration with background color, message background color, and contrast text color
|
||||
const LOG_TYPES = {
|
||||
"log": {
|
||||
"bg_color": "#2d2d2d",
|
||||
"message_bg_color": "#3d3d3d",
|
||||
"text_color": "#ffffff"
|
||||
},
|
||||
"info": {
|
||||
"bg_color": "#2563eb",
|
||||
"message_bg_color": "#3b82f6",
|
||||
"text_color": "#ffffff"
|
||||
},
|
||||
"warning": {
|
||||
"bg_color": "#fbbf24",
|
||||
"message_bg_color": "#fcd34d",
|
||||
"text_color": "#ffffff"
|
||||
},
|
||||
"error": {
|
||||
"bg_color": "#dc2626",
|
||||
"message_bg_color": "#ef4444",
|
||||
"text_color": "#ffffff"
|
||||
},
|
||||
"debug": {
|
||||
"bg_color": "#7c3aed",
|
||||
"message_bg_color": "#a78bfa",
|
||||
"text_color": "#ffffff"
|
||||
}
|
||||
}
|
||||
|
||||
## Contrast text color that works on all backgrounds
|
||||
const CONTRAST_TEXT = "#ffffff"
|
||||
|
||||
## Predefined colors for special peer IDs
|
||||
const SPECIAL_PEER_COLORS = {
|
||||
"SERVER": {
|
||||
"bg_color": "#7c3aed",
|
||||
"text_color": "#ffffff"
|
||||
},
|
||||
"DISCONNECTED": {
|
||||
"bg_color": "#6b7280",
|
||||
"text_color": "#ffffff"
|
||||
}
|
||||
}
|
||||
|
||||
const PEER_COLOR_PALETTE = [
|
||||
{"bg_color": "#10b981", "text_color": "#ffffff"}, # emerald green
|
||||
{"bg_color": "#06b6d4", "text_color": "#ffffff"}, # cyan
|
||||
{"bg_color": "#ec4899", "text_color": "#ffffff"}, # fuchsia pink
|
||||
{"bg_color": "#f97316", "text_color": "#ffffff"}, # orange
|
||||
{"bg_color": "#14b8a6", "text_color": "#ffffff"}, # teal
|
||||
{"bg_color": "#84cc16", "text_color": "#000000"}, # lime green
|
||||
{"bg_color": "#0ea5e9", "text_color": "#ffffff"}, # sky blue
|
||||
{"bg_color": "#22c55e", "text_color": "#ffffff"}, # green
|
||||
{"bg_color": "#e11d48", "text_color": "#ffffff"}, # rose red
|
||||
{"bg_color": "#d946ef", "text_color": "#ffffff"}, # magenta
|
||||
]
|
||||
|
||||
## Background color for the entire log line
|
||||
const LOG_LINE_BG_COLOR = "#1a1a1a"
|
||||
|
||||
## Background color for the script/function name column
|
||||
const SCRIPT_FUNCTION_BG_COLOR = "#4a5a6a"
|
||||
|
||||
## Background color for the local time column (between log type and peer id)
|
||||
const TIMESTAMP_BG_COLOR = "#1e3a5f"
|
||||
#===================================================================================#
|
||||
|
||||
# WIDTHS
|
||||
#===================================================================================#
|
||||
## Column widths for alignment (in characters)
|
||||
const PEER_ID_COLUMN_WIDTH = 10
|
||||
const LOG_TYPE_COLUMN_WIDTH = 8
|
||||
## Default mm:ss:ms; with SHOW_TIMESTAMP_HOURS, hh:mm:ss:ms
|
||||
const TIMESTAMP_COLUMN_WIDTH_MMSSMS = 9
|
||||
const TIMESTAMP_COLUMN_WIDTH_HHMMSSMS = 12
|
||||
const SCRIPT_FUNCTION_COLUMN_WIDTH = 40
|
||||
#===================================================================================#
|
||||
|
||||
# CONFIGURATION
|
||||
#===================================================================================#
|
||||
## Cache for peer ID colors to ensure consistency
|
||||
var _peer_color_cache: Dictionary = {}
|
||||
|
||||
## Enable/disable showing script name and function name in logs
|
||||
@export var SHOW_SCRIPT_NAME = true
|
||||
@export var SHOW_FUNCTION_NAME = true
|
||||
## When false (default), timestamp is local mm:ss:ms. When true, local hh:mm:ss:ms (wider column).
|
||||
@export var SHOW_TIMESTAMP_HOURS = false
|
||||
#===================================================================================#
|
||||
|
||||
# GETTERS
|
||||
#===================================================================================#
|
||||
func _get_peer_id() -> String:
|
||||
"""Get the current peer ID, or return a default identifier if not connected."""
|
||||
if multiplayer == null:
|
||||
return "DISCONNECTED"
|
||||
|
||||
# Check if we're the server (server always has ID 1, but we check is_server() for clarity)
|
||||
if multiplayer.is_server():
|
||||
return "SERVER"
|
||||
|
||||
# Get the unique ID (will be 1 for server, or random positive int > 1 for clients)
|
||||
var peer_id = multiplayer.get_unique_id()
|
||||
return str(peer_id)
|
||||
|
||||
func _get_peer_color_config(peer_id_str: String) -> Dictionary:
|
||||
"""Get color configuration for a peer ID string."""
|
||||
# Check special peer IDs first
|
||||
if SPECIAL_PEER_COLORS.has(peer_id_str):
|
||||
return SPECIAL_PEER_COLORS[peer_id_str]
|
||||
|
||||
# Check cache
|
||||
if _peer_color_cache.has(peer_id_str):
|
||||
return _peer_color_cache[peer_id_str]
|
||||
|
||||
# Generate consistent color based on peer ID
|
||||
# Try to parse the peer_id_str as a number
|
||||
var peer_id_num = peer_id_str.to_int()
|
||||
var color_index: int
|
||||
if peer_id_num > 0:
|
||||
color_index = peer_id_num % PEER_COLOR_PALETTE.size()
|
||||
else:
|
||||
# If parsing fails, use hash of the string for consistency
|
||||
var hash_value = peer_id_str.hash()
|
||||
color_index = abs(hash_value) % PEER_COLOR_PALETTE.size()
|
||||
|
||||
var color_config = PEER_COLOR_PALETTE[color_index].duplicate()
|
||||
_peer_color_cache[peer_id_str] = color_config
|
||||
return color_config
|
||||
|
||||
#===================================================================================#
|
||||
|
||||
# FORMATTERS
|
||||
#===================================================================================#
|
||||
func _format_message(message: String, args: Array = []) -> String:
|
||||
"""Format message with optional arguments."""
|
||||
if args.is_empty():
|
||||
return message
|
||||
|
||||
var formatted = message
|
||||
for i in range(args.size()):
|
||||
formatted = formatted.replace("{" + str(i) + "}", str(args[i]))
|
||||
|
||||
return formatted
|
||||
|
||||
func _format_rich_text(text: String, bg_color: String, text_color: String) -> String:
|
||||
"""Format text with background and text colors using BBCode."""
|
||||
return "[bgcolor=%s][color=%s]%s[/color][/bgcolor]" % [bg_color, text_color, text]
|
||||
|
||||
func _format_space_with_bg(bg_color: String) -> String:
|
||||
"""Format a space character with a background color."""
|
||||
return "[bgcolor=%s] [/bgcolor]" % bg_color
|
||||
|
||||
func _get_padding(text_length: int, width: int) -> String:
|
||||
"""Get padding string for a given text length and target width."""
|
||||
if text_length >= width:
|
||||
return ""
|
||||
var padding = ""
|
||||
for i in range(width - text_length):
|
||||
padding += " "
|
||||
return padding
|
||||
|
||||
func _pad_text(text: String, width: int) -> String:
|
||||
"""Pad text to a specific width for column alignment."""
|
||||
return text + _get_padding(text.length(), width)
|
||||
|
||||
func _truncate_text(text: String, max_length: int) -> String:
|
||||
"""Truncate text to a maximum length."""
|
||||
if text.length() <= max_length:
|
||||
return text
|
||||
return text.substr(0, max_length)
|
||||
|
||||
func _get_local_timestamp_string() -> String:
|
||||
"""Local time: mm:ss:ms by default, or hh:mm:ss:ms when SHOW_TIMESTAMP_HOURS is true."""
|
||||
var unix = Time.get_unix_time_from_system()
|
||||
var ms = clampi(int(floor(fmod(unix, 1.0) * 1000.0)), 0, 999)
|
||||
var t = Time.get_time_dict_from_system()
|
||||
if SHOW_TIMESTAMP_HOURS:
|
||||
return "%02d:%02d:%02d:%03d" % [t.hour, t.minute, t.second, ms]
|
||||
return "%02d:%02d:%03d" % [t.minute, t.second, ms]
|
||||
|
||||
#===================================================================================#
|
||||
|
||||
# PRINT
|
||||
#===================================================================================#
|
||||
func _print_rich_log(peer_id_str: String, log_type: String, message: String, script_name: String = "", function_name: String = "") -> void:
|
||||
"""Print a rich formatted log with peer ID and log type colors."""
|
||||
var peer_color = _get_peer_color_config(peer_id_str)
|
||||
var log_config = LOG_TYPES.get(log_type, LOG_TYPES["log"])
|
||||
|
||||
# Use peer ID directly without "Peer" prefix
|
||||
var peer_label = peer_id_str
|
||||
var log_type_label = log_type.to_upper()
|
||||
|
||||
# Pad peer ID column for alignment
|
||||
var peer_padded = _pad_text(peer_label, PEER_ID_COLUMN_WIDTH)
|
||||
|
||||
# Format peer ID with its background color
|
||||
var peer_formatted = _format_rich_text(peer_padded, peer_color.bg_color, peer_color.text_color)
|
||||
|
||||
# Format log type with its background color
|
||||
var log_type_padded = _pad_text(log_type_label, LOG_TYPE_COLUMN_WIDTH)
|
||||
var log_type_formatted = _format_rich_text(log_type_padded, log_config.bg_color, log_config.text_color)
|
||||
|
||||
# Local time column (between log type and peer id)
|
||||
var ts_width = TIMESTAMP_COLUMN_WIDTH_HHMMSSMS if SHOW_TIMESTAMP_HOURS else TIMESTAMP_COLUMN_WIDTH_MMSSMS
|
||||
var time_padded = _pad_text(_get_local_timestamp_string(), ts_width)
|
||||
var time_formatted = _format_rich_text(time_padded, TIMESTAMP_BG_COLOR, CONTRAST_TEXT)
|
||||
|
||||
# Build the context string (script name and function name) combined in one column
|
||||
var context_string = ""
|
||||
var script_function_parts: Array[String] = []
|
||||
|
||||
if SHOW_SCRIPT_NAME and script_name != "":
|
||||
var script_truncated = _truncate_text(script_name, 18)
|
||||
script_function_parts.append(script_truncated)
|
||||
|
||||
if SHOW_FUNCTION_NAME and function_name != "":
|
||||
var function_truncated = _truncate_text(function_name, 20)
|
||||
script_function_parts.append(function_truncated)
|
||||
|
||||
if not script_function_parts.is_empty():
|
||||
# Combine script and function names with a separator
|
||||
var combined = "::".join(script_function_parts)
|
||||
# Pad, then format with custom background color (so whitespace has background too)
|
||||
var combined_padded = _pad_text(combined, SCRIPT_FUNCTION_COLUMN_WIDTH)
|
||||
var combined_formatted = _format_rich_text(combined_padded, SCRIPT_FUNCTION_BG_COLOR, log_config.text_color)
|
||||
context_string = combined_formatted
|
||||
|
||||
# Format message with text color only (no background)
|
||||
var message_formatted = "[color=%s]%s[/color]" % [log_config.text_color, message]
|
||||
|
||||
# Format spaces with peer ID background color
|
||||
var peer_space = _format_space_with_bg(peer_color.bg_color)
|
||||
|
||||
# Combine log type, context, and message with peer-colored spaces
|
||||
var peer_and_message = peer_formatted
|
||||
if context_string != "":
|
||||
peer_and_message += peer_space + context_string
|
||||
peer_and_message += peer_space + message_formatted
|
||||
|
||||
# Create the full log line: log type, timestamp, then peer id and message
|
||||
var log_line = log_type_formatted + time_formatted + peer_and_message
|
||||
var wrapped_line = "[bgcolor=%s]%s[/bgcolor]" % [LOG_LINE_BG_COLOR, log_line]
|
||||
|
||||
print_rich(wrapped_line)
|
||||
|
||||
#===================================================================================#
|
||||
|
||||
# CALLERS
|
||||
#===================================================================================#
|
||||
func log(message: String, args: Array = [], script_name: String = "", function_name: String = "") -> void:
|
||||
"""Basic log function with peer_id prefix."""
|
||||
var formatted = _format_message(message, args)
|
||||
var peer_id_str = _get_peer_id()
|
||||
_print_rich_log(peer_id_str, "log", formatted, script_name, function_name)
|
||||
|
||||
func info(message: String, args: Array = [], script_name: String = "", function_name: String = "") -> void:
|
||||
"""Log an informational message."""
|
||||
var formatted = _format_message(message, args)
|
||||
var peer_id_str = _get_peer_id()
|
||||
_print_rich_log(peer_id_str, "info", formatted, script_name, function_name)
|
||||
|
||||
func warning(message: String, args: Array = [], script_name: String = "", function_name: String = "") -> void:
|
||||
"""Log a warning message."""
|
||||
var formatted = _format_message(message, args)
|
||||
var peer_id_str = _get_peer_id()
|
||||
_print_rich_log(peer_id_str, "warning", formatted, script_name, function_name)
|
||||
|
||||
func error(message: String, args: Array = [], script_name: String = "", function_name: String = "") -> void:
|
||||
"""Log an error message."""
|
||||
var formatted = _format_message(message, args)
|
||||
var peer_id_str = _get_peer_id()
|
||||
_print_rich_log(peer_id_str, "error", formatted, script_name, function_name)
|
||||
|
||||
func debug(message: String, args: Array = [], script_name: String = "", function_name: String = "") -> void:
|
||||
"""Log a debug message."""
|
||||
var formatted = _format_message(message, args)
|
||||
var peer_id_str = _get_peer_id()
|
||||
_print_rich_log(peer_id_str, "debug", formatted, script_name, function_name)
|
||||
#===================================================================================#
|
||||
@@ -0,0 +1 @@
|
||||
uid://cdfw054e8nhxv
|
||||
@@ -88,6 +88,7 @@ Shared INventory
|
||||
|
||||
## NEtwork TOTO
|
||||
- Make gamemanager a node with syncroniser
|
||||
- All stations
|
||||
|
||||
- Client purchases don't spawn
|
||||
- All stations need syncronizers
|
||||
- Pickable not synced cooked burger on hob example
|
||||
- Client purchases don't spawn items from shop. RPC adventure
|
||||
- Client can not move stations including hobs, on_move handle drop is called, network pickable authority is given. but station not moved
|
||||
+224
-25
@@ -1,19 +1,201 @@
|
||||
class_name GameManager
|
||||
extends Node
|
||||
|
||||
const STAR_DAY_FREQUENCY: int = 3
|
||||
|
||||
static var money: int = 1000
|
||||
static var day_number: int = 1
|
||||
static var meals_in_play: Array[String]
|
||||
static var sides_in_play: Array[String]
|
||||
var money: int = 1000:
|
||||
get: return money
|
||||
|
||||
func set_money(value):
|
||||
if multiplayer.is_server():
|
||||
money = max(0,value)
|
||||
client_sync_money.rpc(money)
|
||||
SweetLogger.info("set_money money set to {0}", [money], "GameManager.gd", "set_money")
|
||||
else:
|
||||
SweetLogger.info("set_money client/(peer_id={0}) attempted to set money directly, sending request to server", [multiplayer.get_unique_id()], "GameManager.gd", "set_money")
|
||||
server_set_money.rpc_id(1, value)
|
||||
|
||||
@rpc("any_peer", "call_remote", "reliable") # CLIENT -> SERVER: Request a change
|
||||
func server_set_money(value: int) -> void: set_money(value)
|
||||
|
||||
@rpc("authority", "call_remote", "reliable") # SERVER -> CLIENTS: Replicate new change
|
||||
func client_sync_money(value: int) -> void: money = value
|
||||
|
||||
|
||||
var day_number: int = 1:
|
||||
get:
|
||||
return day_number
|
||||
|
||||
func set_day_number(value: int) -> void:
|
||||
if multiplayer.is_server():
|
||||
day_number = value
|
||||
client_sync_day_number.rpc(day_number)
|
||||
SweetLogger.info("set_day_number day_number set to {0}", [day_number], "GameManager.gd", "set_day_number")
|
||||
else:
|
||||
SweetLogger.info("set_day_number client/(peer_id={0}) attempted to set day_number directly, sending request to server", [multiplayer.get_unique_id()], "GameManager.gd", "set_day_number")
|
||||
server_set_day_number.rpc_id(1, value)
|
||||
|
||||
@rpc("any_peer", "call_remote", "reliable")
|
||||
func server_set_day_number(value: int) -> void:
|
||||
set_day_number(value)
|
||||
|
||||
@rpc("authority", "call_remote", "reliable")
|
||||
func client_sync_day_number(value: int) -> void:
|
||||
day_number = value
|
||||
|
||||
|
||||
var meals_in_play: Array[String] = []:
|
||||
get:
|
||||
return meals_in_play
|
||||
|
||||
func set_meals_in_play(value: Array[String]) -> void:
|
||||
if multiplayer.is_server():
|
||||
meals_in_play = value
|
||||
client_sync_meals_in_play.rpc(meals_in_play)
|
||||
SweetLogger.info("set_meals_in_play meals_in_play set to {0}", [meals_in_play], "GameManager.gd", "set_meals_in_play")
|
||||
else:
|
||||
SweetLogger.info("set_meals_in_play client/(peer_id={0}) attempted to set meals_in_play directly, sending request to server", [multiplayer.get_unique_id()], "GameManager.gd", "set_meals_in_play")
|
||||
server_set_meals_in_play.rpc_id(1, value)
|
||||
|
||||
@rpc("any_peer", "call_remote", "reliable")
|
||||
func server_set_meals_in_play(value: Array[String]) -> void:
|
||||
set_meals_in_play(value)
|
||||
|
||||
@rpc("authority", "call_remote", "reliable")
|
||||
func client_sync_meals_in_play(value: Array[String]) -> void:
|
||||
meals_in_play = value
|
||||
|
||||
|
||||
var sides_in_play: Array[String] = []:
|
||||
get:
|
||||
return sides_in_play
|
||||
|
||||
func set_sides_in_play(value: Array[String]) -> void:
|
||||
if multiplayer.is_server():
|
||||
sides_in_play = value
|
||||
client_sync_sides_in_play.rpc(sides_in_play)
|
||||
SweetLogger.info("set_sides_in_play sides_in_play set to {0}", [sides_in_play], "GameManager.gd", "set_sides_in_play")
|
||||
else:
|
||||
SweetLogger.info("set_sides_in_play client/(peer_id={0}) attempted to set sides_in_play directly, sending request to server", [multiplayer.get_unique_id()], "GameManager.gd", "set_sides_in_play")
|
||||
server_set_sides_in_play.rpc_id(1, value)
|
||||
|
||||
@rpc("any_peer", "call_remote", "reliable")
|
||||
func server_set_sides_in_play(value: Array[String]) -> void:
|
||||
set_sides_in_play(value)
|
||||
|
||||
@rpc("authority", "call_remote", "reliable")
|
||||
func client_sync_sides_in_play(value: Array[String]) -> void:
|
||||
sides_in_play = value
|
||||
|
||||
|
||||
# GameConfig - difficulty settings
|
||||
static var day_length_seconds: float = 60.0
|
||||
static var customers_per_day: float = 5.0
|
||||
static var customers_count_increase_per_day: float = 1.0
|
||||
static var group_min_size: int = 1
|
||||
static var group_max_size: int = 2
|
||||
var day_length_seconds: float = 60.0:
|
||||
get:
|
||||
return day_length_seconds
|
||||
|
||||
func set_day_length_seconds(value: float) -> void:
|
||||
if multiplayer.is_server():
|
||||
day_length_seconds = value
|
||||
client_sync_day_length_seconds.rpc(day_length_seconds)
|
||||
SweetLogger.info("set_day_length_seconds day_length_seconds set to {0}", [day_length_seconds], "GameManager.gd", "set_day_length_seconds")
|
||||
else:
|
||||
SweetLogger.info("set_day_length_seconds client/(peer_id={0}) attempted to set day_length_seconds directly, sending request to server", [multiplayer.get_unique_id()], "GameManager.gd", "set_day_length_seconds")
|
||||
server_set_day_length_seconds.rpc_id(1, value)
|
||||
|
||||
@rpc("any_peer", "call_remote", "reliable")
|
||||
func server_set_day_length_seconds(value: float) -> void:
|
||||
set_day_length_seconds(value)
|
||||
|
||||
@rpc("authority", "call_remote", "reliable")
|
||||
func client_sync_day_length_seconds(value: float) -> void:
|
||||
day_length_seconds = value
|
||||
|
||||
|
||||
var customers_per_day: float = 5.0:
|
||||
get:
|
||||
return customers_per_day
|
||||
|
||||
func set_customers_per_day(value: float) -> void:
|
||||
if multiplayer.is_server():
|
||||
customers_per_day = value
|
||||
client_sync_customers_per_day.rpc(customers_per_day)
|
||||
SweetLogger.info("set_customers_per_day customers_per_day set to {0}", [customers_per_day], "GameManager.gd", "set_customers_per_day")
|
||||
else:
|
||||
SweetLogger.info("set_customers_per_day client/(peer_id={0}) attempted to set customers_per_day directly, sending request to server", [multiplayer.get_unique_id()], "GameManager.gd", "set_customers_per_day")
|
||||
server_set_customers_per_day.rpc_id(1, value)
|
||||
|
||||
@rpc("any_peer", "call_remote", "reliable")
|
||||
func server_set_customers_per_day(value: float) -> void:
|
||||
set_customers_per_day(value)
|
||||
|
||||
@rpc("authority", "call_remote", "reliable")
|
||||
func client_sync_customers_per_day(value: float) -> void:
|
||||
customers_per_day = value
|
||||
|
||||
|
||||
var customers_count_increase_per_day: float = 1.0:
|
||||
get:
|
||||
return customers_count_increase_per_day
|
||||
|
||||
func set_customers_count_increase_per_day(value: float) -> void:
|
||||
if multiplayer.is_server():
|
||||
customers_count_increase_per_day = value
|
||||
client_sync_customers_count_increase_per_day.rpc(customers_count_increase_per_day)
|
||||
SweetLogger.info("set_customers_count_increase_per_day customers_count_increase_per_day set to {0}", [customers_count_increase_per_day], "GameManager.gd", "set_customers_count_increase_per_day")
|
||||
else:
|
||||
SweetLogger.info("set_customers_count_increase_per_day client/(peer_id={0}) attempted to set customers_count_increase_per_day directly, sending request to server", [multiplayer.get_unique_id()], "GameManager.gd", "set_customers_count_increase_per_day")
|
||||
server_set_customers_count_increase_per_day.rpc_id(1, value)
|
||||
|
||||
@rpc("any_peer", "call_remote", "reliable")
|
||||
func server_set_customers_count_increase_per_day(value: float) -> void:
|
||||
set_customers_count_increase_per_day(value)
|
||||
|
||||
@rpc("authority", "call_remote", "reliable")
|
||||
func client_sync_customers_count_increase_per_day(value: float) -> void:
|
||||
customers_count_increase_per_day = value
|
||||
|
||||
|
||||
var group_min_size: int = 1:
|
||||
get:
|
||||
return group_min_size
|
||||
|
||||
func set_group_min_size(value: int) -> void:
|
||||
if multiplayer.is_server():
|
||||
group_min_size = value
|
||||
client_sync_group_min_size.rpc(group_min_size)
|
||||
SweetLogger.info("set_group_min_size group_min_size set to {0}", [group_min_size], "GameManager.gd", "set_group_min_size")
|
||||
else:
|
||||
SweetLogger.info("set_group_min_size client/(peer_id={0}) attempted to set group_min_size directly, sending request to server", [multiplayer.get_unique_id()], "GameManager.gd", "set_group_min_size")
|
||||
server_set_group_min_size.rpc_id(1, value)
|
||||
|
||||
@rpc("any_peer", "call_remote", "reliable")
|
||||
func server_set_group_min_size(value: int) -> void:
|
||||
set_group_min_size(value)
|
||||
|
||||
@rpc("authority", "call_remote", "reliable")
|
||||
func client_sync_group_min_size(value: int) -> void:
|
||||
group_min_size = value
|
||||
|
||||
|
||||
var group_max_size: int = 2:
|
||||
get:
|
||||
return group_max_size
|
||||
|
||||
func set_group_max_size(value: int) -> void:
|
||||
if multiplayer.is_server():
|
||||
group_max_size = value
|
||||
client_sync_group_max_size.rpc(group_max_size)
|
||||
SweetLogger.info("set_group_max_size group_max_size set to {0}", [group_max_size], "GameManager.gd", "set_group_max_size")
|
||||
else:
|
||||
SweetLogger.info("set_group_max_size client/(peer_id={0}) attempted to set group_max_size directly, sending request to server", [multiplayer.get_unique_id()], "GameManager.gd", "set_group_max_size")
|
||||
server_set_group_max_size.rpc_id(1, value)
|
||||
|
||||
@rpc("any_peer", "call_remote", "reliable")
|
||||
func server_set_group_max_size(value: int) -> void:
|
||||
set_group_max_size(value)
|
||||
|
||||
@rpc("authority", "call_remote", "reliable")
|
||||
func client_sync_group_max_size(value: int) -> void:
|
||||
group_max_size = value
|
||||
|
||||
|
||||
enum GameState {
|
||||
@@ -22,38 +204,55 @@ enum GameState {
|
||||
BUILDING
|
||||
}
|
||||
|
||||
static var game_state: GameState = GameState.BUILDING: set = _set_game_state
|
||||
var game_state: GameState = GameState.BUILDING:
|
||||
get:
|
||||
return game_state
|
||||
|
||||
static func _set_game_state(value: GameState):
|
||||
func set_game_state(value: GameState) -> void:
|
||||
if multiplayer.is_server():
|
||||
game_state = value
|
||||
client_sync_game_state.rpc(game_state)
|
||||
Signals.game_state_changed.emit(game_state)
|
||||
SweetLogger.info("set_game_state game_state set to {0}", [game_state], "GameManager.gd", "set_game_state")
|
||||
else:
|
||||
SweetLogger.info("set_game_state client/(peer_id={0}) attempted to set game_state directly, sending request to server", [multiplayer.get_unique_id()], "GameManager.gd", "set_game_state")
|
||||
server_set_game_state.rpc_id(1, value)
|
||||
|
||||
@rpc("any_peer", "call_remote", "reliable")
|
||||
func server_set_game_state(value: GameState) -> void:
|
||||
set_game_state(value)
|
||||
|
||||
@rpc("authority", "call_remote", "reliable")
|
||||
func client_sync_game_state(value: GameState) -> void:
|
||||
game_state = value
|
||||
Signals.game_state_changed.emit(value)
|
||||
Signals.game_state_changed.emit(game_state)
|
||||
|
||||
|
||||
static func _restart():
|
||||
print("restart Game")
|
||||
game_state = GameState.RUNNING
|
||||
|
||||
|
||||
static func get_random_meal() -> String:
|
||||
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])
|
||||
SweetLogger.debug("get_random_meal() returning {0}", [meals_in_play[rand_index]], "GameManager.gd", "get_random_meal")
|
||||
return meals_in_play[rand_index]
|
||||
|
||||
|
||||
static func get_random_side() -> String:
|
||||
print("GameManager: get_random_side() ")
|
||||
func get_random_side() -> String:
|
||||
SweetLogger.debug("get_random_side()", [], "GameManager.gd", "get_random_side")
|
||||
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() list=%s returning %s" % [sides_in_play, sides_in_play[rand_index]])
|
||||
SweetLogger.debug("get_random_side() list={0} returning {1}", [sides_in_play, sides_in_play[rand_index]], "GameManager.gd", "get_random_side")
|
||||
return sides_in_play[rand_index]
|
||||
|
||||
|
||||
static func game_over():
|
||||
print("Game Over")
|
||||
func _restart():
|
||||
SweetLogger.info("restart Game", [], "GameManager.gd", "_restart")
|
||||
game_state = GameState.RUNNING
|
||||
|
||||
|
||||
func game_over():
|
||||
SweetLogger.info("Game Over", [], "GameManager.gd", "game_over")
|
||||
game_state = GameState.GAME_OVER
|
||||
Signals.game_over.emit()
|
||||
|
||||
+14
-14
@@ -111,22 +111,22 @@ static func get_item_scene(item_id: StringName) -> PackedScene:
|
||||
static func print_all_recipes() -> void:
|
||||
load_recipes()
|
||||
if not _loaded:
|
||||
print("RecipeManager: could not load recipes.yaml; no recipes printed.")
|
||||
SweetLogger.warning("could not load recipes.yaml; no recipes printed.", [], "RecipeManager.gd", "print_all_recipes")
|
||||
return
|
||||
|
||||
if _combining_map.is_empty():
|
||||
print("RecipeManager: no combining recipes found")
|
||||
SweetLogger.warning("no combining recipes found", [], "RecipeManager.gd", "print_all_recipes")
|
||||
return
|
||||
|
||||
print("#### RecipeManager: Loaded recipes ####")
|
||||
SweetLogger.info("#### RecipeManager: Loaded recipes ####", [], "RecipeManager.gd", "print_all_recipes")
|
||||
_print_combining_recipes()
|
||||
print("")
|
||||
SweetLogger.info("", [], "RecipeManager.gd", "print_all_recipes")
|
||||
_print_cooking_recipes()
|
||||
print("")
|
||||
SweetLogger.info("", [], "RecipeManager.gd", "print_all_recipes")
|
||||
_print_chopping_recipes()
|
||||
print("")
|
||||
SweetLogger.info("", [], "RecipeManager.gd", "print_all_recipes")
|
||||
_print_rolling_recipes()
|
||||
print("")
|
||||
SweetLogger.info("", [], "RecipeManager.gd", "print_all_recipes")
|
||||
_print_augmenting_recipes()
|
||||
|
||||
static func _print_combining_recipes() -> void:
|
||||
@@ -135,12 +135,12 @@ static func _print_combining_recipes() -> void:
|
||||
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)
|
||||
SweetLogger.warning("invalid combining map key '{0}'", [key_str], "RecipeManager.gd", "_print_combining_recipes")
|
||||
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])
|
||||
SweetLogger.info(" {0} <-combine-- {1} + {2}", [result_id, first, second], "RecipeManager.gd", "_print_combining_recipes")
|
||||
|
||||
|
||||
static func _print_cooking_recipes() -> void:
|
||||
@@ -148,22 +148,22 @@ static func _print_cooking_recipes() -> void:
|
||||
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"]])
|
||||
SweetLogger.info(" {0} <-cook-- {1} - time: {2}", [cooked_id, cook_def["ingredient"], cook_def["time"]], "RecipeManager.gd", "_print_cooking_recipes")
|
||||
else:
|
||||
var cook_def = cook_defs
|
||||
print(" %s <-cook-- %s - time: %.1f" % [cooked_id, cook_def["ingredient"], cook_def["time"]])
|
||||
SweetLogger.info(" {0} <-cook-- {1} - time: {2}", [cooked_id, cook_def["ingredient"], cook_def["time"]], "RecipeManager.gd", "_print_cooking_recipes")
|
||||
|
||||
|
||||
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"]])
|
||||
SweetLogger.info(" {0} <-chop-- {1} - work: {2}", [chopped_id, chop_def["ingredient"], chop_def["work"]], "RecipeManager.gd", "_print_chopping_recipes")
|
||||
|
||||
|
||||
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"]])
|
||||
SweetLogger.info(" {0} <-roll-- {1} - work: {2}", [rolled_id, roll_def["ingredient"], roll_def["work"]], "RecipeManager.gd", "_print_rolling_recipes")
|
||||
|
||||
|
||||
static func _print_augmenting_recipes() -> void:
|
||||
@@ -171,7 +171,7 @@ static func _print_augmenting_recipes() -> void:
|
||||
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])
|
||||
SweetLogger.info(" {0} <-augment-- {1} adds attribute '{2}'", [target_id, ingredient_id, attr_key], "RecipeManager.gd", "_print_augmenting_recipes")
|
||||
|
||||
|
||||
static func _build_scene_paths() -> void:
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
extends Node
|
||||
|
||||
@warning_ignore("unused_signal")
|
||||
signal game_over
|
||||
@warning_ignore("unused_signal")
|
||||
signal restart_game
|
||||
@warning_ignore("unused_signal")
|
||||
signal game_state_changed(new_state: GameManager.GameState)
|
||||
@warning_ignore("unused_signal")
|
||||
signal station_bought(instance: Node3D)
|
||||
@warning_ignore("unused_signal")
|
||||
signal request_customer_spawn()
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
extends Node
|
||||
|
||||
func _ready() -> void:
|
||||
if OS.has_feature("editor"):
|
||||
# Force subwindows to be native OS windows instead of embedded viewports
|
||||
get_tree().root.gui_embed_subwindows = false
|
||||
get_tree().create_timer(0.05).timeout.connect(_position_window)
|
||||
|
||||
func _position_window() -> void:
|
||||
var is_server: bool = OS.get_cmdline_args().has("--server")
|
||||
var screen_rect: Rect2i = DisplayServer.screen_get_usable_rect(DisplayServer.window_get_current_screen())
|
||||
|
||||
var window_width: int = screen_rect.size.x / 2
|
||||
var window_height: int = int(screen_rect.size.y * (2.0 / 3.0))
|
||||
|
||||
DisplayServer.window_set_size(Vector2i(window_width - 10, window_height))
|
||||
|
||||
var x_pos: int = screen_rect.position.x + window_width if is_server else screen_rect.position.x
|
||||
DisplayServer.window_set_position(Vector2i(x_pos, screen_rect.position.y))
|
||||
@@ -0,0 +1 @@
|
||||
uid://de8j52uus1pbv
|
||||
@@ -2,7 +2,7 @@ extends Node
|
||||
|
||||
func _unhandled_input(event: InputEvent) -> void:
|
||||
if event.is_action_pressed("quit_game"):
|
||||
get_tree().quit()
|
||||
all_quit_game.rpc()
|
||||
if event.is_action_pressed("satisfy_table_orders"):
|
||||
satisfy_table_orders()
|
||||
if event.is_action_pressed("set_building_mode"):
|
||||
@@ -12,6 +12,10 @@ func _unhandled_input(event: InputEvent) -> void:
|
||||
if event.is_action_pressed("set_game_over"):
|
||||
set_game_over()
|
||||
|
||||
# Kill all clients
|
||||
@rpc("any_peer", "call_local", "reliable")
|
||||
func all_quit_game():
|
||||
get_tree().quit()
|
||||
|
||||
# Finds any node of class/type Table and calls satisfyAllOrders()
|
||||
func satisfy_table_orders() -> void:
|
||||
@@ -24,14 +28,14 @@ func satisfy_table_orders() -> void:
|
||||
|
||||
|
||||
func set_buidling_mode():
|
||||
print("Global key event: Setting building mode")
|
||||
GameManager.game_state = GameManager.GameState.BUILDING
|
||||
SweetLogger.info("Setting building mode", [], "global_key_events.gd", "set_buidling_mode")
|
||||
GameManager.set_game_state(GameManager.GameState.BUILDING)
|
||||
|
||||
|
||||
func set_running_mode():
|
||||
print("Global key event: Setting running mode")
|
||||
GameManager.game_state = GameManager.GameState.RUNNING
|
||||
SweetLogger.info("Setting running mode", [], "global_key_events.gd", "set_running_mode")
|
||||
GameManager.set_game_state(GameManager.GameState.RUNNING)
|
||||
|
||||
func set_game_over():
|
||||
print("Global key event: Setting game over")
|
||||
GameManager.game_state = GameManager.GameState.GAME_OVER
|
||||
SweetLogger.info("Setting game over", [], "global_key_events.gd", "set_game_over")
|
||||
GameManager.set_game_state(GameManager.GameState.GAME_OVER)
|
||||
|
||||
+3
-3
@@ -25,15 +25,15 @@ static func find_first_child_of_type(node: Node, type: Variant) -> Node:
|
||||
# Returns true if decendant is a decendant node of root, false otherwise. Returns false if either node is null.
|
||||
static func is_node_decendant_of(decendant: Node, root: Node) -> bool:
|
||||
if not decendant or not root:
|
||||
print("Helper.is_node_decendant_of: decendant or root is null")
|
||||
SweetLogger.debug("is_node_decendant_of: decendant or root is null", [], "helper.gd", "is_node_decendant_of")
|
||||
return false
|
||||
var current: Node = decendant
|
||||
while current:
|
||||
if current == root:
|
||||
print("Helper.is_node_decendant_of: decendant %s is a descendant of root %s" % [decendant.name, root.name])
|
||||
SweetLogger.debug("is_node_decendant_of: decendant {0} is a descendant of root {1}", [decendant.name, root.name], "helper.gd", "is_node_decendant_of")
|
||||
return true
|
||||
current = current.get_parent()
|
||||
print("Helper.is_node_decendant_of: decendant %s is NOT a descendant of root %s" % [decendant.name, root.name])
|
||||
SweetLogger.debug("is_node_decendant_of: decendant {0} is NOT a descendant of root {1}", [decendant.name, root.name], "helper.gd", "is_node_decendant_of")
|
||||
return false
|
||||
|
||||
|
||||
|
||||
+5
-2
@@ -22,6 +22,9 @@ XRToolsRumbleManager="*uid://by853dk86g1qw"
|
||||
NetworkManager="*res://Net/network_manager.gd"
|
||||
GlobalKeyEvents="*uid://c60unagog5oi1"
|
||||
Signals="*uid://fuux6cxfjwdc"
|
||||
GameManager="*uid://y4sol8l8vih1"
|
||||
SweetLogger="*uid://cdfw054e8nhxv"
|
||||
MoveWindows="*uid://de8j52uus1pbv"
|
||||
|
||||
[debug]
|
||||
|
||||
@@ -31,13 +34,13 @@ file_logging/enable_file_logging=true
|
||||
|
||||
window/size/viewport_width=1000
|
||||
window/size/viewport_height=650
|
||||
window/size/mode=2
|
||||
window/size/initial_position_type=0
|
||||
window/stretch/mode="canvas_items"
|
||||
window/stretch/aspect="expand"
|
||||
|
||||
[editor_plugins]
|
||||
|
||||
enabled=PackedStringArray("res://addons/godot-xr-tools/plugin.cfg", "res://addons/kanban_tasks/plugin.cfg", "res://addons/yaml/plugin.cfg")
|
||||
enabled=PackedStringArray("res://addons/godot-xr-tools/plugin.cfg", "res://addons/kanban_tasks/plugin.cfg", "res://addons/sweet-logger/plugin.cfg", "res://addons/yaml/plugin.cfg")
|
||||
|
||||
[filesystem]
|
||||
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
uid://be8o8m6xpp3kc
|
||||
+30
-30
@@ -86,7 +86,7 @@ var _frame_index := 0
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
var args := OS.get_cmdline_user_args()
|
||||
var args := OS.get_cmdline_args()
|
||||
_auto_mode = "--mptest" in args
|
||||
# Opt-in only. This node also sits in the real multiplayer scene (so a client
|
||||
# joining a test session has a driver), and must be completely inert during
|
||||
@@ -176,10 +176,10 @@ var _despawn_timers_seen := {}
|
||||
|
||||
# Items live either baked in the scene root or, once spawned at runtime, under
|
||||
# WorldContent. Look in both.
|
||||
func _find(name: String) -> Node3D:
|
||||
var n := _world.get_node_or_null(name)
|
||||
func _find(node_name: String) -> Node3D:
|
||||
var n := _world.get_node_or_null(node_name)
|
||||
if not n:
|
||||
n = _world.get_node_or_null("WorldContent/" + name)
|
||||
n = _world.get_node_or_null("WorldContent/" + node_name)
|
||||
return n as Node3D
|
||||
|
||||
|
||||
@@ -788,7 +788,7 @@ func _setup_frames() -> void:
|
||||
_frames_enabled = false
|
||||
_log("frame capture disabled: a headless run has no rendered output to grab")
|
||||
return
|
||||
var role := "server" if "--server" in OS.get_cmdline_user_args() else "client"
|
||||
var role := "server" if "--server" in OS.get_cmdline_args() else "client"
|
||||
_frames_dir = "res://logs/mptest_frames_%s" % role
|
||||
DirAccess.make_dir_recursive_absolute(ProjectSettings.globalize_path(_frames_dir))
|
||||
# Clear out a previous run's frames, or the GIF would splice the two together.
|
||||
@@ -965,10 +965,10 @@ func _snapshot() -> Dictionary:
|
||||
for child in root.get_children():
|
||||
if child is XRToolsPickable and not child.is_queued_for_deletion():
|
||||
out[str(child.name)] = _describe(child)
|
||||
for name in WATCHED_STATIONS:
|
||||
var station := _find(name)
|
||||
for station_name in WATCHED_STATIONS:
|
||||
var station := _find(station_name)
|
||||
if station:
|
||||
out["station:" + name] = _describe_station(station)
|
||||
out["station:" + station_name] = _describe_station(station)
|
||||
return out
|
||||
|
||||
|
||||
@@ -1016,37 +1016,37 @@ func _fetch_client_snapshot() -> Dictionary:
|
||||
# Compare the server's view with the client's, returning a list of differences.
|
||||
func _compare(server: Dictionary, client: Dictionary) -> Array[String]:
|
||||
var problems: Array[String] = []
|
||||
for name in server:
|
||||
if not client.has(name):
|
||||
problems.append("'%s' exists on the server but NOT on the client" % name)
|
||||
for name in client:
|
||||
if not server.has(name):
|
||||
problems.append("'%s' exists on the client but NOT on the server (ghost copy)" % name)
|
||||
for name in server:
|
||||
if not client.has(name):
|
||||
for entity_name in server:
|
||||
if not client.has(entity_name):
|
||||
problems.append("'%s' exists on the server but NOT on the client" % entity_name)
|
||||
for entity_name in client:
|
||||
if not server.has(entity_name):
|
||||
problems.append("'%s' exists on the client but NOT on the server (ghost copy)" % entity_name)
|
||||
for entity_name in server:
|
||||
if not client.has(entity_name):
|
||||
continue
|
||||
var s: Dictionary = server[name]
|
||||
var c: Dictionary = client[name]
|
||||
var s: Dictionary = server[entity_name]
|
||||
var c: Dictionary = client[entity_name]
|
||||
# Stations are compared on their displayed state, not a position.
|
||||
if s.has("pos") and c.has("pos"):
|
||||
var dist: float = (s["pos"] as Vector3).distance_to(c["pos"])
|
||||
if dist > SYNC_POS_TOLERANCE:
|
||||
problems.append("%s is %.3fm apart (server %s vs client %s)" % [name, dist, s["pos"], c["pos"]])
|
||||
problems.append("%s is %.3fm apart (server %s vs client %s)" % [entity_name, dist, s["pos"], c["pos"]])
|
||||
for key in s:
|
||||
# "_" keys are per-peer diagnostics, not things that must match.
|
||||
if key == "pos" or key.begins_with("_"):
|
||||
continue
|
||||
if s[key] != c[key]:
|
||||
problems.append("%s.%s: server=%s client=%s" % [name, key, s[key], c[key]])
|
||||
problems.append("%s.%s: server=%s client=%s" % [entity_name, key, s[key], c[key]])
|
||||
# Absolute invariants, checked per peer. A cross-peer diff can't catch a
|
||||
# fault that happens identically on both sides.
|
||||
for peer_name in ["server", "client"]:
|
||||
var snap: Dictionary = server if peer_name == "server" else client
|
||||
for name in snap:
|
||||
var d: Dictionary = snap[name]
|
||||
for entity_name in snap:
|
||||
var d: Dictionary = snap[entity_name]
|
||||
if d.has("visuals_attached") and not d["visuals_attached"]:
|
||||
problems.append("on the %s, %s's food has come off the plate (%.3fm from it, limit %.2f)"
|
||||
% [peer_name, name, d.get("_visual_offset", -1.0), MAX_VISUAL_OFFSET])
|
||||
% [peer_name, entity_name, d.get("_visual_offset", -1.0), MAX_VISUAL_OFFSET])
|
||||
return problems
|
||||
|
||||
|
||||
@@ -1368,17 +1368,17 @@ func _assert_debug_camera() -> void:
|
||||
func _check_framing() -> void:
|
||||
var size := get_viewport().get_visible_rect().size
|
||||
var offscreen: Array[String] = []
|
||||
for name in ["Counter2", "Counter", "Hob", "Sink", "DirtStation", "Plate"]:
|
||||
var n := _find(name)
|
||||
for station_name in ["Counter2", "Counter", "Hob", "Sink", "DirtStation", "Plate"]:
|
||||
var n := _find(station_name)
|
||||
if not n:
|
||||
continue
|
||||
var p := _debug_cam.unproject_position(n.global_position)
|
||||
var frac := Vector2(p.x / size.x, p.y / size.y)
|
||||
var on := not _debug_cam.is_position_behind(n.global_position) \
|
||||
and frac.x > 0.02 and frac.x < 0.98 and frac.y > 0.02 and frac.y < 0.98
|
||||
_log(" framing: %-12s at %.2f,%.2f of frame%s" % [name, frac.x, frac.y, "" if on else " <-- OFF SCREEN"])
|
||||
_log(" framing: %-12s at %.2f,%.2f of frame%s" % [station_name, frac.x, frac.y, "" if on else " <-- OFF SCREEN"])
|
||||
if not on:
|
||||
offscreen.append(name)
|
||||
offscreen.append(station_name)
|
||||
if offscreen.is_empty():
|
||||
_log(" framing: all test objects are in view")
|
||||
else:
|
||||
@@ -1410,7 +1410,7 @@ func _banner(s: String) -> void:
|
||||
# would otherwise fight over one file (the engine's own godot.log has exactly
|
||||
# that problem when two peers run at once — it rotates per process).
|
||||
func _open_log() -> void:
|
||||
var role := "server" if "--server" in OS.get_cmdline_user_args() else "client"
|
||||
var role := "server" if "--server" in OS.get_cmdline_args() else "client"
|
||||
var path := "res://logs/mptest_%s.log" % role
|
||||
DirAccess.make_dir_recursive_absolute(ProjectSettings.globalize_path("res://logs"))
|
||||
_log_file = FileAccess.open(path, FileAccess.WRITE)
|
||||
@@ -1419,11 +1419,11 @@ func _open_log() -> void:
|
||||
path = OS.get_environment("TEMP").path_join("vryhungry_mptest_%s.log" % role)
|
||||
_log_file = FileAccess.open(path, FileAccess.WRITE)
|
||||
_log_path = ProjectSettings.globalize_path(path)
|
||||
print("[MPTEST] step log -> %s" % _log_path)
|
||||
SweetLogger.info("[MPTEST] step log -> {0}", [_log_path], "mp_test_driver.gd", "_open_log")
|
||||
|
||||
|
||||
func _log(s: String) -> void:
|
||||
print("[MPTEST %s] %s" % [_role, s])
|
||||
SweetLogger.info("[MPTEST {0}] {1}", [_role, s], "mp_test_driver.gd", "_log")
|
||||
if _log_file:
|
||||
_log_file.store_line(s)
|
||||
_log_file.flush()
|
||||
|
||||
@@ -42,7 +42,7 @@ func _run() -> void:
|
||||
_clear_previous_results(logs_dir)
|
||||
|
||||
print_rich("[b]Running the multiplayer test suite...[/b]")
|
||||
print(" the editor will be unresponsive until it finishes (~2 minutes)")
|
||||
SweetLogger.info("the editor will be unresponsive until it finishes (~2 minutes)", [], "run_tests_in_editor.gd", "_run")
|
||||
|
||||
var server_pid := _launch(exe, project_dir, ["--server"], SERVER_SCENE)
|
||||
if server_pid <= 0:
|
||||
@@ -61,7 +61,7 @@ func _run() -> void:
|
||||
OS.delay_msec(500)
|
||||
waited += 0.5
|
||||
if OS.is_process_running(server_pid):
|
||||
print(" timed out after %ds, stopping the instances" % TIMEOUT_SEC)
|
||||
SweetLogger.warning("timed out after {0}s, stopping the instances", [TIMEOUT_SEC], "run_tests_in_editor.gd", "_run")
|
||||
OS.kill(server_pid)
|
||||
if OS.is_process_running(client_pid):
|
||||
OS.kill(client_pid)
|
||||
@@ -108,7 +108,7 @@ func _print_report(logs_dir: String) -> void:
|
||||
push_error("No report at %s — the run did not finish. Check logs/mptest_server.log" % path)
|
||||
return
|
||||
var text := FileAccess.get_file_as_string(path)
|
||||
print("")
|
||||
SweetLogger.info("", [], "run_tests_in_editor.gd", "_print_report")
|
||||
# Colour the summary so a failure is obvious in the Output panel.
|
||||
for line in text.split("\n"):
|
||||
if line.begins_with("FAIL") or line.contains("RESULT: FAILED"):
|
||||
@@ -118,8 +118,8 @@ func _print_report(logs_dir: String) -> void:
|
||||
elif line.begins_with("PASS"):
|
||||
print_rich("[color=gray]%s[/color]" % line)
|
||||
else:
|
||||
print(line)
|
||||
print("report: %s" % path)
|
||||
SweetLogger.info("{0}", [line], "run_tests_in_editor.gd", "_print_report")
|
||||
SweetLogger.info("report: {0}", [path], "run_tests_in_editor.gd", "_print_report")
|
||||
|
||||
|
||||
func _build_gif(project_dir: String, logs_dir: String) -> void:
|
||||
|
||||
@@ -3,8 +3,8 @@ extends Node
|
||||
|
||||
# Called when the node enters the scene tree for the first time.
|
||||
func _ready() -> void:
|
||||
print(get_stations())
|
||||
print(get_items())
|
||||
SweetLogger.debug("stations: {0}", [get_stations()], "testworldLoad.gd", "_ready")
|
||||
SweetLogger.debug("items: {0}", [get_items()], "testworldLoad.gd", "_ready")
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user