Merge branch 'feat/nicknames' into 'develop'

 Working profile names in-game, basic settings save/load system, flag drops on player death

See merge request open-fpsz/open-fpsz!39
This commit is contained in:
Squinty 2024-04-16 21:39:08 +00:00
commit 63e39bbe15
12 changed files with 122 additions and 67 deletions

View file

@ -1,6 +1,24 @@
# This file is part of open-fpsz.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
class_name FlagCarryComponent extends Node
## This component allows its entity to grab, carry and throw flags
##
## To work correctly the owner MUST set an attachment point for carried flags
## and a sensor to detect when flags are within grab range
@export var throw_velocity : float = 10.0
@export var max_throw_speed : float = 10.0
@export var attachment : Node3D
@export var sensor : Area3D
@ -20,11 +38,12 @@ func _grab(flag : Flag):
flag.grab()
_carried_flag = flag
func throw():
@rpc("call_local")
func _drop(throw_speed : float):
if _is_carrying():
_carried_flag.drop()
_carried_flag.linear_velocity = attachment.global_basis.z * throw_velocity
_carried_flag.rotation_degrees.x = 0.0
_carried_flag.linear_velocity = attachment.global_basis.z * throw_speed
_carried_flag = null
func _is_carrying() -> bool:
@ -33,3 +52,9 @@ func _is_carrying() -> bool:
func _sensor_on_body_entered(collider):
if collider is Flag:
_grab.rpc(collider)
func drop():
_drop.rpc(0.0)
func throw():
_drop.rpc(max_throw_speed)

View file

@ -1,15 +1,15 @@
# This file is part of open-fpsz.
#
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
class_name HealthComponent extends Area3D

View file

@ -1,12 +1,8 @@
[gd_scene load_steps=3 format=3 uid="uid://bof3mg7wgxrmn"]
[gd_scene load_steps=2 format=3 uid="uid://bof3mg7wgxrmn"]
[ext_resource type="Script" path="res://components/health_component.gd" id="1_00xis"]
[ext_resource type="Shape3D" uid="uid://dkwljsgaflf31" path="res://entities/player/collision_shape.res" id="2_sgbmt"]
[node name="HealthComponent" type="Area3D"]
collision_layer = 4
collision_mask = 0
script = ExtResource("1_00xis")
[node name="CollisionShape3D" type="CollisionShape3D" parent="."]
shape = ExtResource("2_sgbmt")

Binary file not shown.

View file

@ -0,0 +1,4 @@
[gd_resource type="CapsuleShape3D" format=3 uid="uid://cb8esdlnottdn"]
[resource]
radius = 0.25

View file

@ -36,6 +36,7 @@ enum PlayerState { PLAYER_ALIVE, PLAYER_DEAD }
set(id):
player_id = id
$PlayerInput.set_multiplayer_authority(id)
@export var nickname : String
@onready var input : PlayerInput = $PlayerInput
@onready var camera = $SpringArm3D/Camera3D
@ -45,7 +46,7 @@ enum PlayerState { PLAYER_ALIVE, PLAYER_DEAD }
@onready var weapon = $SpringArm3D/Inventory/SpaceGun
@onready var animation_player : AnimationPlayer = $AnimationPlayer
@onready var health_component = $HealthComponent
@onready var flag_carry_component = $FlagCarryComponent
@onready var flag_carry_component : FlagCarryComponent = $FlagCarryComponent
@onready var spring_arm_height = $SpringArm3D.position.y
@onready var _original_weapon_transform : Transform3D = weapon.transform
@onready var flag_carry_attachment = $SpringArm3D/FlagCarryAttachment
@ -65,7 +66,6 @@ func _ready():
health_component.health_zeroed.connect(_die)
if _is_first_person():
camera.current = true
flag_carry_attachment.hide()
remove_child($ThirdPerson)
else:
remove_child($HUD)
@ -214,6 +214,11 @@ func _die():
if _is_first_person():
animation_player.stop()
)
flag_carry_component.drop()
@rpc("call_local")
func set_nickname(value):
nickname = value
func respawn(location):
linear_velocity = Vector3()

View file

@ -1,8 +1,8 @@
[gd_scene load_steps=21 format=3 uid="uid://cbhx1xme0sb7k"]
[ext_resource type="Script" path="res://entities/player/player.gd" id="1_mk68k"]
[ext_resource type="Shape3D" uid="uid://dkwljsgaflf31" path="res://entities/player/collision_shape.res" id="2_8rtw3"]
[ext_resource type="PackedScene" uid="uid://drbefw6akui2v" path="res://entities/player/assets/vanguard.tscn" id="2_beyex"]
[ext_resource type="Shape3D" uid="uid://cb8esdlnottdn" path="res://entities/player/collision_shape.tres" id="2_vjqny"]
[ext_resource type="PackedScene" uid="uid://bcv81ku26xo" path="res://interfaces/hud/hud.tscn" id="3_ccety"]
[ext_resource type="PackedScene" uid="uid://c8co0qa2omjmh" path="res://weapons/space_gun/space_gun.tscn" id="4_lhn5w"]
[ext_resource type="PackedScene" uid="uid://dn1tcakam5egs" path="res://weapons/space_gun/projectile.tscn" id="5_lvaut"]
@ -180,6 +180,9 @@ properties/3/replication_mode = 2
properties/4/path = NodePath(".:player_state")
properties/4/spawn = true
properties/4/replication_mode = 2
properties/5/path = NodePath(".:nickname")
properties/5/spawn = true
properties/5/replication_mode = 2
[sub_resource type="SceneReplicationConfig" id="SceneReplicationConfig_5j4ew"]
properties/0/path = NodePath(".:direction")
@ -210,11 +213,11 @@ visible = false
mesh = SubResource("CapsuleMesh_vmqfq")
[node name="CollisionShape3D" type="CollisionShape3D" parent="."]
shape = ExtResource("2_8rtw3")
shape = ExtResource("2_vjqny")
[node name="ShapeCast3D" type="ShapeCast3D" parent="."]
transform = Transform3D(1.05, 0, 0, 0, 1.05, 0, 0, 0, 1.05, 0, 0, 0)
shape = ExtResource("2_8rtw3")
shape = ExtResource("2_vjqny")
target_position = Vector3(0, 0, 0)
collision_mask = 2147483656
collide_with_areas = true
@ -225,7 +228,7 @@ collision_mask = 8
monitorable = false
[node name="CollisionShape3D" type="CollisionShape3D" parent="Sensor"]
shape = ExtResource("2_8rtw3")
shape = ExtResource("2_vjqny")
[node name="HUD" parent="." instance=ExtResource("3_ccety")]
@ -252,8 +255,10 @@ transform = Transform3D(-1, 0, -8.74228e-08, 0, 1, 0, 8.74228e-08, 0, -1, 0, -0.
[node name="HealthComponent" parent="." instance=ExtResource("5_t6i6e")]
[node name="CollisionShape3D" type="CollisionShape3D" parent="HealthComponent"]
shape = ExtResource("2_vjqny")
[node name="FlagCarryComponent" parent="." node_paths=PackedStringArray("attachment", "sensor") instance=ExtResource("7_e7s1a")]
throw_velocity = 20.0
attachment = NodePath("../SpringArm3D/FlagCarryAttachment")
sensor = NodePath("../Sensor")

View file

@ -1,15 +1,15 @@
# This file is part of open-fpsz.
#
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
extends Node2D
@ -28,7 +28,7 @@ func _process(_delta):
else:
_v_box_container.show()
_player_name_label.text = player.name
_player_name_label.text = player.nickname
position = camera.unproject_position(attach_point.global_position)
var viewport_size : Vector2 = get_viewport_rect().size
position.x = clampf(position.x, 0, viewport_size.x - _v_box_container.size.x)

View file

@ -1,4 +1,4 @@
[gd_scene load_steps=7 format=3 uid="uid://bjctlqvs33nqy"]
[gd_scene load_steps=6 format=3 uid="uid://bjctlqvs33nqy"]
[ext_resource type="Texture2D" uid="uid://c1tjamjm8qjog" path="res://interfaces/menus/boot/background.webp" id="1_ph586"]
@ -10,6 +10,13 @@ signal start_demo
func _on_demo_pressed():
start_demo.emit()
func _on_multiplayer_pressed():
$Main.hide()
$Multiplayer.show()
func _on_quit_pressed():
get_tree().quit()
"
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_krqeq"]
@ -20,9 +27,11 @@ script/source = "class_name MultiplayerPanel extends PanelContainer
const DEFAULT_HOST : String = \"localhost\"
const DEFAULT_PORT : int = 9000
const CONFIG_FILE_PATH : String = \"user://settings.cfg\"
var _join_address = RegEx.new()
var _registered_ports = RegEx.new()
var _join_address : RegEx = RegEx.new()
var _registered_ports : RegEx = RegEx.new()
var _config_file : ConfigFile = ConfigFile.new()
signal start_server(port)
signal join_server(host, port)
@ -34,8 +43,21 @@ func _ready():
# see https://datatracker.ietf.org/doc/html/rfc1700
_registered_ports.compile(r'^(?:102[4-9]|10[3-9]\\d|1[1-9]\\d{2}|[2-9]\\d{3}|[1-5]\\d{4}|6[0-4]\\d{3}|65[0-4]\\d{2}|655[0-2]\\d|6553[0-5])$')
_join_address.compile(r'^(?<host>[a-zA-Z0-9.-]+)(:(?<port>:102[4-9]|10[3-9]\\d|1[1-9]\\d{2}|[2-9]\\d{3}|[1-5]\\d{4}|6[0-4]\\d{3}|65[0-4]\\d{2}|655[0-2]\\d|6553[0-5]))?$')
_load_config()
hide() # start hidden
func _load_config():
var error : Error = _config_file.load(CONFIG_FILE_PATH)
if error != OK:
return
var profile_name : String = _config_file.get_value(\"profile\", \"name\", \"Newblood\")
%ProfileName.text = profile_name
func _on_save_pressed():
_config_file.set_value(\"profile\", \"name\", %ProfileName.text)
_config_file.save(CONFIG_FILE_PATH)
func _on_menu_pressed():
hide()
owner.get_node(\"Main\").show()
@ -53,8 +75,8 @@ func _on_host_pressed():
else: # port is not valid
push_warning(\"A valid port number in the range 1024-65535 is required.\")
return
start_server.emit(port)
start_server.emit(port, %ProfileName.text)
func _on_join_pressed():
var addr = [DEFAULT_HOST, DEFAULT_PORT]
@ -66,7 +88,7 @@ func _on_join_pressed():
if rport: addr[1] = int(rport)
$Modal.show()
join_server.emit(addr[0], addr[1])
join_server.emit(addr[0], addr[1], %ProfileName.text)
func _on_connected_to_server():
$Modal.hide()
@ -79,17 +101,6 @@ func _on_connection_failed():
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_snh7i"]
bg_color = Color(0, 0.5, 0.5, 0.25)
[sub_resource type="GDScript" id="GDScript_yqbr7"]
script/source = "extends PanelContainer
func _on_multiplayer_pressed():
hide()
owner.get_node(\"Multiplayer\").show()
func _on_quit_pressed():
get_tree().quit()
"
[node name="BootMenu" type="CanvasLayer"]
script = SubResource("GDScript_jd8xf")
@ -156,6 +167,10 @@ layout_mode = 2
disabled = true
text = "Delete"
[node name="Save" type="Button" parent="Multiplayer/MarginContainer/TabContainer/Profile/MarginContainer/HBoxContainer/LeftBox"]
layout_mode = 2
text = "Save"
[node name="Spacer" type="MarginContainer" parent="Multiplayer/MarginContainer/TabContainer/Profile/MarginContainer/HBoxContainer/LeftBox"]
layout_mode = 2
size_flags_vertical = 3
@ -313,7 +328,6 @@ offset_right = 313.0
grow_vertical = 2
size_flags_horizontal = 0
theme_override_styles/panel = SubResource("StyleBoxFlat_snh7i")
script = SubResource("GDScript_yqbr7")
[node name="MarginContainer" type="MarginContainer" parent="Main"]
layout_mode = 2
@ -342,6 +356,7 @@ text = "Quit"
[connection signal="join_server" from="Multiplayer" to="." method="_on_multiplayer_join_server"]
[connection signal="start_server" from="Multiplayer" to="." method="_on_multiplayer_start_server"]
[connection signal="pressed" from="Multiplayer/MarginContainer/TabContainer/Profile/MarginContainer/HBoxContainer/LeftBox/Save" to="Multiplayer" method="_on_save_pressed"]
[connection signal="pressed" from="Multiplayer/MarginContainer/TabContainer/Profile/MarginContainer/HBoxContainer/LeftBox/Menu" to="Multiplayer" method="_on_menu_pressed"]
[connection signal="pressed" from="Multiplayer/MarginContainer/TabContainer/Profile/MarginContainer/HBoxContainer/LeftBox/Quit" to="Multiplayer" method="_on_quit_pressed"]
[connection signal="pressed" from="Multiplayer/MarginContainer/TabContainer/Join/MarginContainer/HBoxContainer/LeftBox/Join" to="Multiplayer" method="_on_join_pressed"]
@ -352,5 +367,5 @@ text = "Quit"
[connection signal="pressed" from="Multiplayer/MarginContainer/TabContainer/Host/MarginContainer/HBoxContainer/LeftBox/Quit" to="Multiplayer" method="_on_quit_pressed"]
[connection signal="text_changed" from="Multiplayer/MarginContainer/TabContainer/Host/MarginContainer/HBoxContainer/RightBox/ServerPort" to="Multiplayer/MarginContainer/TabContainer/Host/MarginContainer/HBoxContainer/RightBox/ServerPort" method="_on_text_changed"]
[connection signal="pressed" from="Main/MarginContainer/VBoxContainer/Demo" to="." method="_on_demo_pressed"]
[connection signal="pressed" from="Main/MarginContainer/VBoxContainer/Multiplayer" to="Main" method="_on_multiplayer_pressed"]
[connection signal="pressed" from="Main/MarginContainer/VBoxContainer/Quit" to="Main" method="_on_quit_pressed"]
[connection signal="pressed" from="Main/MarginContainer/VBoxContainer/Multiplayer" to="." method="_on_multiplayer_pressed"]
[connection signal="pressed" from="Main/MarginContainer/VBoxContainer/Quit" to="." method="_on_quit_pressed"]

View file

@ -24,20 +24,20 @@ func _start_demo():
add_child(mode)
$BootMenu.hide()
func _start_server(port):
func _start_server(port, nickname):
if mode: mode.queue_free()
mode = MULTIPLAYER.instantiate()
add_child(mode)
mode.start_server(port)
mode.start_server(port, nickname)
$BootMenu.hide()
func _join_server(host, port):
func _join_server(host, port, nickname):
if mode: mode.queue_free()
mode = MULTIPLAYER.instantiate()
add_child(mode)
mode.connected_to_server.connect($BootMenu/Multiplayer._on_connected_to_server)
mode.connection_failed.connect($BootMenu/Multiplayer._on_connection_failed)
mode.join_server(host, port)
mode.join_server(host, port, nickname)
func _unhandled_input(event):
# exit the program

View file

@ -23,7 +23,7 @@ signal connection_failed
func load_map(scene : PackedScene):
map.add_child(scene.instantiate())
func start_server(port):
func start_server(port, nickname):
var peer = ENetMultiplayerPeer.new()
peer.create_server(port, MAX_CLIENTS)
@ -34,23 +34,21 @@ func start_server(port):
multiplayer.peer_connected.connect(add_player)
multiplayer.peer_disconnected.connect(remove_player)
for id in multiplayer.get_peers():
add_player(id)
if DisplayServer.get_name() != \"headless\":
add_player(1)
add_player(1, nickname)
add_flag()
func join_server(host, port):
func join_server(host, port, nickname):
var peer = ENetMultiplayerPeer.new()
peer.create_client(host, port)
multiplayer.connected_to_server.connect(_on_connected_to_server)
multiplayer.connected_to_server.connect(_on_connected_to_server.bind(nickname))
multiplayer.connection_failed.connect(_on_connection_failed)
multiplayer.multiplayer_peer = peer
func _on_connected_to_server():
func _on_connected_to_server(nickname):
connected_to_server.emit()
_join_match.rpc(nickname)
func _on_connection_failed():
connection_failed.emit()
@ -58,10 +56,11 @@ func _on_connection_failed():
func respawn_player(player):
player.respawn(Vector3(0.0, 150.0, 0.0))
func add_player(peer_id : int):
func add_player(peer_id : int, nickname : String):
var player : Player = PLAYER.instantiate()
player.name = str(peer_id)
player.player_id = peer_id
player.nickname = nickname
player.position = Vector3(0.0, 150.0, 0.0)
players.add_child(player)
player.died.connect(respawn_player)
@ -73,6 +72,12 @@ func remove_player(peer_id : int):
players.get_node(node_name).queue_free()
print(\"Peer `%s` disconnected\" % node_name)
@rpc(\"any_peer\")
func _join_match(nickname):
if multiplayer.is_server():
add_player(multiplayer.get_remote_sender_id(), nickname)
func add_flag():
var flag : Flag = FLAG.instantiate()
flag.position = Vector3(5.0, 100.0, 0.0)

View file

@ -1,15 +1,15 @@
# This file is part of open-fpsz.
#
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
class_name Trail3D extends MeshInstance3D
@ -54,7 +54,7 @@ func _process(delta):
if(_old_pos - get_global_transform().origin).length() > _motion_delta and _trail_enabled:
_append_point() # Create new point
_old_pos = get_global_transform().origin # Update previous position to current position coordinates
# Update the lifespan
var p = 0
var max_points = _points.size()
@ -64,29 +64,29 @@ func _process(delta):
_remove_point(p)
p -= 1
if (p < 0): p = 0
max_points = _points.size()
p += 1
mesh.clear_surfaces()
# If less than 2 points, stop rendering trail
if _points.size() < 2:
return
# Render new mesh for each point
mesh.surface_begin(Mesh.PRIMITIVE_TRIANGLE_STRIP)
for i in range(_points.size()):
var t = float(i) / (_points.size() - 1.0)
var curr_color = _start_color.lerp(_end_color, 1 - t)
mesh.surface_set_color(curr_color)
var curr_width = _widths[i][0] - pow(1 - t, _scale_acceleration) * _widths[i][1]
var t0 = i / _points.size()
var t1 = t
mesh.surface_set_uv(Vector2(t0, 0))
mesh.surface_add_vertex(to_local(_points[i] + curr_width))
mesh.surface_set_uv(Vector2(t1, 1))