diff --git a/assets/core/enviroment/dev-level/dev-level.tscn b/assets/core/enviroment/dev-level/dev-level.tscn index f33f1ad..996040e 100644 --- a/assets/core/enviroment/dev-level/dev-level.tscn +++ b/assets/core/enviroment/dev-level/dev-level.tscn @@ -1,6 +1,5 @@ -[gd_scene load_steps=5 format=3 uid="uid://ewovs6ns5y3k"] +[gd_scene load_steps=4 format=3 uid="uid://ewovs6ns5y3k"] -[ext_resource type="PackedScene" uid="uid://c6w0ivy4hetrl" path="res://assets/core/player-controller/scenes/player.tscn" id="2_q510b"] [ext_resource type="PackedScene" uid="uid://y0xb2vktsr1k" path="res://assets/core/ships/shuttle-class/shuttle-class.tscn" id="3_lsckv"] [ext_resource type="PackedScene" uid="uid://dqymnaouq1mu2" path="res://assets/core/enviroment/dev-level/terrain.tscn" id="3_vcq2f"] [ext_resource type="PackedScene" uid="uid://dlv4cwhskx8dr" path="res://assets/core/enviroment/custom-skies/sky.tscn" id="4_uss2e"] diff --git a/assets/core/networking/scenes/lobby.tscn b/assets/core/networking/scenes/lobby.tscn index 6f54eec..e339666 100644 --- a/assets/core/networking/scenes/lobby.tscn +++ b/assets/core/networking/scenes/lobby.tscn @@ -3,7 +3,7 @@ [ext_resource type="Script" path="res://assets/core/networking/scripts/lobby.gd" id="1_o4fbq"] [ext_resource type="PackedScene" uid="uid://biryul3n6thlw" path="res://assets/core/networking/scenes/user_box_prefab.tscn" id="2_dpthk"] -[node name="Lobby" type="Control" node_paths=PackedStringArray("host_button", "join_button", "leave_button", "lobby_id_line_edit", "user_list_box")] +[node name="Lobby" type="Control" node_paths=PackedStringArray("host_button", "leave_button", "start_button", "user_list_box")] layout_mode = 3 anchors_preset = 15 anchor_right = 1.0 @@ -12,9 +12,8 @@ grow_horizontal = 2 grow_vertical = 2 script = ExtResource("1_o4fbq") host_button = NodePath("Panel/HBoxContainer/Buttons/Host") -join_button = NodePath("Panel/HBoxContainer/Buttons/HBoxContainer/Join") leave_button = NodePath("Panel/HBoxContainer/Buttons/Leave") -lobby_id_line_edit = NodePath("Panel/HBoxContainer/Buttons/HBoxContainer/LineEdit") +start_button = NodePath("Panel/HBoxContainer/Buttons/Start") user_list_box = NodePath("Panel/HBoxContainer/PlayerList") user_box_prefab = ExtResource("2_dpthk") @@ -45,23 +44,16 @@ layout_mode = 2 size_flags_vertical = 4 text = "Host Lobby" -[node name="HBoxContainer" type="HBoxContainer" parent="Panel/HBoxContainer/Buttons"] -layout_mode = 2 - -[node name="LineEdit" type="LineEdit" parent="Panel/HBoxContainer/Buttons/HBoxContainer"] -layout_mode = 2 -size_flags_horizontal = 3 - -[node name="Join" type="Button" parent="Panel/HBoxContainer/Buttons/HBoxContainer"] -custom_minimum_size = Vector2(90, 0) -layout_mode = 2 -text = "Join" - [node name="Leave" type="Button" parent="Panel/HBoxContainer/Buttons"] layout_mode = 2 disabled = true text = "Leave Lobby" +[node name="Start" type="Button" parent="Panel/HBoxContainer/Buttons"] +layout_mode = 2 +disabled = true +text = "Start" + [node name="PlayerList" type="VBoxContainer" parent="Panel/HBoxContainer"] layout_mode = 2 size_flags_horizontal = 3 diff --git a/assets/core/networking/scripts/NetworkManager.gd b/assets/core/networking/scripts/NetworkManager.gd index 3ed5d8c..edbc168 100644 --- a/assets/core/networking/scripts/NetworkManager.gd +++ b/assets/core/networking/scripts/NetworkManager.gd @@ -4,6 +4,9 @@ const STEAM_APP_ID: int = 480 const PACKET_READ_LIMIT: int = 32 +var level_scene: PackedScene +var player_scene: PackedScene + var lobby_data var lobby_id: int = 0 var lobby_members: Array = [] @@ -13,16 +16,25 @@ var lobby_type: int = Steam.LOBBY_TYPE_PUBLIC var steam_id: int = 0 var steam_username: String = "" var avatar_texture_cache: Dictionary = {} -var host_id: int = 0 +var is_host: bool = false + +var uuid_counter: int = 0 + +var node_map: Dictionary = {} signal lobby_created(lobby_id: int) signal lobby_joined(lobby_id: int) signal user_joined_lobby(user_id: int) signal user_left_lobby(user_id: int) signal host_left_lobby() +signal on_game_started() + +signal property_update_received(node_id: int, property_name: String, value: Variant) func _ready() -> void: + player_scene = load("res://assets/core/player-controller/scenes/player.tscn") as PackedScene + level_scene = load("res://assets/core/enviroment/dev-level/dev-level.tscn") as PackedScene _init_steam() @@ -190,6 +202,7 @@ func _on_p2p_session_connect_fail(steam_id: int, session_error: int) -> void: func host_lobby(): if lobby_id == 0: Steam.createLobby(lobby_type, lobby_members_max) + is_host = true else: printerr("Cannot host lobby, already in a lobby") @@ -250,6 +263,7 @@ func send_p2p_packet(target: int, packet_data: Dictionary) -> void: for this_member in lobby_members: if this_member['steam_id'] != steam_id: Steam.sendP2PPacket(this_member['steam_id'], this_data, send_type, channel) + #print("Sent packet to %s." % this_member['steam_name']) # Else send it to someone specific else: @@ -284,8 +298,32 @@ func read_p2p_packet() -> void: # Decompress the array before turning it into a useable dictionary var readable_data: Dictionary = bytes_to_var(packet_code.decompress_dynamic(-1, FileAccess.COMPRESSION_GZIP)) - # Print the packet to output - print("Packet: %s" % readable_data) + # Handshake packet + if "message" in readable_data and readable_data["message"] == "handshake": + if packet_sender != steam_id: + print("Received handshake packet from %s." % Steam.getFriendPersonaName(packet_sender)) + + # Start game packet + if "message" in readable_data and readable_data["message"] == "start_game": + print("Received game start packet.") + _on_game_started() + + # Property update packet + if "message" in readable_data and readable_data["message"] == "property_update": + if "node_id" in readable_data and "property_name" in readable_data and "value" in readable_data: + emit_signal("property_update_received", readable_data["node_id"], readable_data["property_name"], readable_data["value"]) + #print("Received property update packet for node %d: %s = %s" % [readable_data["node_id"], readable_data["property_name"], readable_data["value"]]) + + +func register_node(node: Node) -> String: + var uuid = generate_uuid() + node_map[uuid] = node + return uuid + + +func generate_uuid() -> String: + uuid_counter += 1 + return str(uuid_counter) func request_player_avatar(user_id: int, size: int = 128) -> void: @@ -316,7 +354,36 @@ func get_player_avatar(user_id: int) -> ImageTexture: await request_player_avatar(user_id) return avatar_texture_cache[user_id] - + +func start_game(): + print("Starting game...") + var packet_data = {"message":"start_game"} + send_p2p_packet(0, packet_data) + _on_game_started() +func _on_game_started(): + print("Game started.") + var level: Node = level_scene.instantiate() + get_tree().root.add_child(level) + on_game_started.emit() + + + for member in lobby_members: + var player: Player = player_scene.instantiate() + player.name = "Player_" + str(member["steam_id"]) + player.username = Steam.getFriendPersonaName(member["steam_id"]) + + if member["steam_id"] == steam_id: + player.is_network_authority = true + else: + player.is_network_authority = false + + level.add_child(player) + + +func sync_property(node_id: String, property_name: String, value: Variant): + var packet_data = {"message":"property_update", "node_id": node_id, "property_name":property_name, "value":value} + send_p2p_packet(0, packet_data) + diff --git a/assets/core/networking/scripts/lobby.gd b/assets/core/networking/scripts/lobby.gd index b843980..f077ffa 100644 --- a/assets/core/networking/scripts/lobby.gd +++ b/assets/core/networking/scripts/lobby.gd @@ -1,9 +1,8 @@ extends Control @export var host_button: Button -@export var join_button: Button @export var leave_button: Button -@export var lobby_id_line_edit: LineEdit +@export var start_button: Button @export var user_list_box: VBoxContainer @export var user_box_prefab: PackedScene @@ -12,13 +11,14 @@ var added_users = [] func _ready() -> void: host_button.pressed.connect(_on_host) - join_button.pressed.connect(_on_join) leave_button.pressed.connect(_on_leave) + start_button.pressed.connect(_on_start) NetworkManager.lobby_created.connect(_on_lobby_created) NetworkManager.lobby_joined.connect(_on_lobby_joined) NetworkManager.user_joined_lobby.connect(_on_user_joined_lobby) NetworkManager.user_left_lobby.connect(_on_user_left_lobby) + NetworkManager.on_game_started.connect(_on_game_started) GameConsole.register_command(Command.new("update", update, [], "Updates the lobby UI")) @@ -27,10 +27,6 @@ func _on_host(): NetworkManager.host_lobby() -func _on_join(): - NetworkManager.join_lobby(int(lobby_id_line_edit.text)) - - func _on_leave(): NetworkManager.leave_lobby() added_users.clear() @@ -40,18 +36,14 @@ func _on_leave(): func _on_lobby_created(lobby_id: int): print("Lobby created") - lobby_id_line_edit.text = str(NetworkManager.lobby_id) host_button.disabled = true - join_button.disabled = true leave_button.disabled = false - lobby_id_line_edit.editable = false + start_button.disabled = false func _on_lobby_joined(lobby_id: int): host_button.disabled = true - join_button.disabled = true leave_button.disabled = false - lobby_id_line_edit.editable = false func _on_user_joined_lobby(user_id: int): @@ -67,6 +59,15 @@ func _on_user_left_lobby(user_id: int): update() +func _on_start(): + NetworkManager.start_game() + visible = false + + +func _on_game_started(): + visible = false + + func update() -> void: for child in user_list_box.get_children(): child.queue_free() diff --git a/assets/core/player-controller/scripts/player.gd b/assets/core/player-controller/scripts/player.gd index 18fe4ea..d79ba97 100644 --- a/assets/core/player-controller/scripts/player.gd +++ b/assets/core/player-controller/scripts/player.gd @@ -4,6 +4,10 @@ var player_tag: Label3D var username: String = "" var is_piloting: bool = false +var is_network_authority: bool = false +var network_uuid: String = "" +var steam_id: int = 0 + @export_category("Player") @export_range(1, 35, 1) var speed: float = 5 # m/s @export_range(10, 400, 1) var acceleration: float = 100 # m/s^2 @@ -19,19 +23,28 @@ var gravity: float = ProjectSettings.get_setting("physics/3d/default_gravity") var move_dir: Vector2 # Input direction for movement var look_dir: Vector2 # Input direction for look/aim -var walk_vel: Vector3 # Walking velocity -var grav_vel: Vector3 # Gravity velocity +var walk_vel: Vector3 # Walking velocity +var grav_vel: Vector3 # Gravity velocity var jump_vel: Vector3 # Jumping velocity var current_ship: Ship +var previous_global_position: Vector3 +var previous_global_rotation: Vector3 func _ready() -> void: - capture_mouse() + NetworkManager.property_update_received.connect(_on_property_update) + network_uuid = NetworkManager.register_node(self) + player_tag = get_node("PlayerTag") + player_tag.text = username + + if is_network_authority: + camera.make_current() func _unhandled_input(event: InputEvent) -> void: + if !is_network_authority: return if Input.mouse_mode == Input.MOUSE_MODE_CAPTURED: if event is InputEventMouseMotion: is_using_joystick = false @@ -42,15 +55,17 @@ func _unhandled_input(event: InputEvent) -> void: if Input.is_action_just_pressed("jump") and !is_piloting: jumping = true - + func _input(event): + if !is_network_authority: return if event.is_action_pressed("esc") and Input.mouse_mode == Input.MOUSE_MODE_CAPTURED: release_mouse() elif event.is_action_pressed("esc") and not Input.mouse_mode == Input.MOUSE_MODE_CAPTURED: capture_mouse() - + func _physics_process(delta: float) -> void: + if !is_network_authority: return if is_piloting and current_ship != null: global_rotation.y = current_ship.global_rotation.y velocity = Vector3.ZERO + _gravity(delta) @@ -59,29 +74,44 @@ func _physics_process(delta: float) -> void: global_rotation.x = 0.0 global_rotation.z = 0.0 - + if Input.mouse_mode == Input.MOUSE_MODE_CAPTURED: _handle_joypad_camera_rotation(delta) move_and_slide() + +func _process(delta: float) -> void: + if !is_network_authority: return + + # If the global_position has changed, notify the NetworkManager + if previous_global_position != global_position: + NetworkManager.sync_property(network_uuid, "global_position", global_position) + previous_global_position = global_position + if previous_global_rotation != global_rotation: + NetworkManager.sync_property(network_uuid, "global_rotation", global_rotation) + previous_global_rotation = global_rotation + func capture_mouse() -> void: + if !is_network_authority: return Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED) - + func release_mouse() -> void: + if !is_network_authority: return Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE) - + func _rotate_camera(sens_mod: float = 1.0) -> void: + if !is_network_authority: return var camera_sens_final = camera_sens if is_using_joystick: camera_sens_final = camera_sens * joystick_camera_sens_multiplier - + camera.rotation.y -= look_dir.x * camera_sens_final * sens_mod camera.rotation.x = clamp(camera.rotation.x - look_dir.y * camera_sens_final * sens_mod, -1.5, 1.5) - + func _handle_joypad_camera_rotation(delta: float, sens_mod: float = 1.0) -> void: var joypad_dir: Vector2 = Input.get_vector("look_left","look_right","look_up","look_down") if joypad_dir.length() > 0: @@ -89,7 +119,7 @@ func _handle_joypad_camera_rotation(delta: float, sens_mod: float = 1.0) -> void _rotate_camera(sens_mod) look_dir = Vector2.ZERO - + func walk(delta: float) -> Vector3: if Input.mouse_mode == Input.MOUSE_MODE_CAPTURED: move_dir = Input.get_vector("move_left", "move_right", "move_forwards", "move_backwards") @@ -98,12 +128,12 @@ func walk(delta: float) -> Vector3: walk_vel = walk_vel.move_toward(walk_dir * speed * move_dir.length(), acceleration * delta) return walk_vel - + func _gravity(delta: float) -> Vector3: grav_vel = Vector3.ZERO if is_on_floor() else grav_vel.move_toward(Vector3(0, velocity.y - gravity, 0), gravity * delta) return grav_vel - + func _jump(delta: float) -> Vector3: if jumping: if is_on_floor(): jump_vel = Vector3(0, sqrt(4 * jump_height * gravity), 0) @@ -112,8 +142,23 @@ func _jump(delta: float) -> Vector3: jump_vel = Vector3.ZERO if is_on_floor() else jump_vel.move_toward(Vector3.ZERO, gravity * delta) return jump_vel + +func player_entered_ship(ship_global_position: Vector3, ship: Ship): + if !is_network_authority: return + current_ship = ship + print(ship.ship_id) + print(global_position) + +func player_exited_ship(ship_global_position: Vector3, ship: Ship): + if !is_network_authority: return + current_ship = null + print(ship.ship_id) + print(global_position) + + func set_is_piloting(state: bool): + if !is_network_authority: return is_piloting = state print("player is piloting: ", str(is_piloting)) @@ -124,3 +169,11 @@ func ship_entered(_ship: Ship): func ship_exited(): current_ship = null + + +func _on_property_update(node_id: String, property_name: String, value: Variant) -> void: + if NetworkManager.node_map.has(node_id): + var node = NetworkManager.node_map[node_id] + node.set(property_name, value) + else: + printerr("Received property update but node_id is wrong? Expected " + str(network_uuid) + " but got " + str(node_id))