Compare commits

..

No commits in common. "rework" and "develop" have entirely different histories.

62 changed files with 1460 additions and 3008 deletions

View File

@ -1,259 +0,0 @@
extends Control
@onready var lobby_name_txt = $CreateLobbyCont/LobbyNameTxt
@onready var lobby_visibility = $CreateLobbyCont/LobbyVisibilityBtn
@onready var max_members = $CreateLobbyCont/MaxMembersBtn
@onready var lobby_member = preload("res://addons/godot_steam_sync/Lobby/lobby_member.tscn")
@onready var lobby_name_lbl = $LobbyPanel/MarginContainer/LobbyCont/Panel/LobbyNameLbl
@onready var start_btn = $LobbyPanel/MarginContainer/LobbyCont/StartBtn
var im_ready : bool = false
func _ready() -> void:
Steam.join_requested.connect(_on_lobby_join_requested)
#Steam.lobby_chat_update.connect(_on_lobby_chat_update)
Steam.lobby_created.connect(_on_lobby_created)
#Steam.lobby_data_update.connect(_on_lobby_data_update)
#Steam.lobby_invite.connect(_on_lobby_invite)
Steam.lobby_joined.connect(_on_lobby_joined)
#Steam.lobby_match_list.connect(_on_lobby_match_list)
#Steam.lobby_message.connect(_on_lobby_message)
Steam.persona_state_change.connect(_on_persona_change)
Steam.p2p_session_request.connect(_on_p2p_session_request)
Steam.p2p_session_connect_fail.connect(_on_p2p_session_connect_fail)
# Check for command line arguments
check_command_line()
func check_command_line() -> void:
var these_arguments: Array = OS.get_cmdline_args()
# There are arguments to process
if these_arguments.size() > 0:
# A Steam connection argument exists
if these_arguments[0] == "+connect_lobby":
# Lobby invite exists so try to connect to it
if int(these_arguments[1]) > 0:
# At this point, you'll probably want to change scenes
# Something like a loading into lobby screen
print("Command line lobby ID: %s" % these_arguments[1])
join_lobby(int(these_arguments[1]))
#region JoinLobbyRegion
func join_lobby(this_lobby_id: int) -> void:
print("Attempting to join lobby %s" % this_lobby_id)
# Clear any previous lobby members lists, if you were in a previous lobby
NetworkManager.LOBBY_MEMBERS.clear()
# Make the lobby join request to Steam
Steam.joinLobby(this_lobby_id)
func _on_lobby_joined(lobby_id: int, _permissions: int, _locked: bool, response: int):
# If joining succeed, this will be 1
if response == 1:
# Set this lobby ID as your lobby ID
NetworkManager.LOBBY_ID = lobby_id
# Print the lobby ID to a label
lobby_name_lbl.set_text(Steam.getLobbyData(NetworkManager.LOBBY_ID,"name"))
# Append to output
print("[STEAM] Joined lobby "+str(NetworkManager.LOBBY_ID)+".\n")
# Get the lobby members
get_lobby_members()
# Make the initial handshake
make_p2p_handshake()
change_lobby_ui(true)
# Else it failed for some reason
else:
# Get the failure reason
var FAIL_REASON: String
match response:
2: FAIL_REASON = "This lobby no longer exists."
3: FAIL_REASON = "You don't have permission to join this lobby."
4: FAIL_REASON = "The lobby is now full."
5: FAIL_REASON = "Uh... something unexpected happened!"
6: FAIL_REASON = "You are banned from this lobby."
7: FAIL_REASON = "You cannot join due to having a limited account."
8: FAIL_REASON = "This lobby is locked or disabled."
9: FAIL_REASON = "This lobby is community locked."
10: FAIL_REASON = "A user in the lobby has blocked you from joining."
11: FAIL_REASON = "A user you have blocked is in the lobby."
$Frame/Main/Displays/Outputs/Output.append_text("[STEAM] Failed joining lobby "+str(lobby_id)+": "+str(FAIL_REASON)+"\n")
# Reopen the server list
#_on_Open_Lobby_List_pressed()
func _on_lobby_join_requested(lobby_id: int, friend_id: int):
# Get the lobby owner's name
var OWNER_NAME = Steam.getFriendPersonaName(friend_id)
print("[STEAM] Joining "+str(OWNER_NAME)+"'s lobby...\n")
# Attempt to join the lobby
join_lobby(lobby_id)
#endregion
func change_lobby_ui(current : bool):
if current:
$CreateLobbyCont.hide()
$LobbyPanel.show()
$MembersPnl.show()
else:
$CreateLobbyCont.show()
$LobbyPanel.hide()
$MembersPnl.hide()
#region CreateLobbyRegion
func _on_create_lobby_btn_pressed():
if NetworkManager.LOBBY_ID == 0:
Steam.createLobby(lobby_visibility.get_selected_id(), int(max_members.get_item_text(max_members.get_selected_id())))
func _on_lobby_created(connect: int, this_lobby_id: int) -> void:
if connect == 1:
# Set the lobby ID
NetworkManager.LOBBY_ID = this_lobby_id
print("Created a lobby: %s" % NetworkManager.LOBBY_ID )
# Set this lobby as joinable, just in case, though this should be done by default
Steam.setLobbyJoinable(NetworkManager.LOBBY_ID, true)
# Set some lobby data
Steam.setLobbyData(NetworkManager.LOBBY_ID, "name", lobby_name_txt.text)
Steam.setLobbyData(NetworkManager.LOBBY_ID, "mode", "Mechatronauts")
# Allow P2P connections to fallback to being relayed through Steam if needed
var set_relay: bool = Steam.allowP2PPacketRelay(true)
get_lobby_members()
change_lobby_ui(true)
#endregion
func get_lobby_members() -> void:
# Clear your previous lobby list
NetworkManager.LOBBY_MEMBERS.clear()
for MEMBER in $MembersPnl/MarginContainer/ScrollContainer/VBoxContainer.get_children():
MEMBER.hide()
MEMBER.queue_free()
# Get the number of members from this lobby from Steam
var num_of_members: int = Steam.getNumLobbyMembers(NetworkManager.LOBBY_ID)
# Get the data of these players from Steam
for this_member in range(0, num_of_members):
# Get the member's Steam ID
var member_steam_id: int = Steam.getLobbyMemberByIndex(NetworkManager.LOBBY_ID, this_member)
# Get the member's Steam name
var member_steam_name: String = Steam.getFriendPersonaName(member_steam_id)
# Add them to the list
add_member_to_list(member_steam_id,member_steam_name)
if NetworkManager.STEAM_ID == Steam.getLobbyOwner(NetworkManager.LOBBY_ID):
NetworkManager.IS_READY[member_steam_id] = false
else:
start_btn.hide()
start_btn.disabled = true
# A user's information has changed
func _on_persona_change(this_steam_id: int, _flag: int) -> void:
# Make sure you're in a lobby and this user is valid or Steam might spam your console log
if NetworkManager.LOBBY_ID > 0:
print("A user (%s) had information change, update the lobby list" % this_steam_id)
# Update the player list
get_lobby_members()
func add_member_to_list(steam_id: int, steam_name: String):
print("Adding new player to the list: "+str(steam_id)+" / "+str(steam_name))
# Add them to the list
NetworkManager.LOBBY_MEMBERS.append({"steam_id":steam_id, "steam_name":steam_name })
# Instance the lobby member object
var THIS_MEMBER: Object = lobby_member.instantiate()
# Add their Steam name and ID
THIS_MEMBER.name = str(steam_id)
THIS_MEMBER._set_Member(steam_id, steam_name)
# Add the child node
$MembersPnl/MarginContainer/ScrollContainer/VBoxContainer.add_child(THIS_MEMBER)
#region P2PHandshake
func make_p2p_handshake() -> void:
print("Sending P2P handshake to the lobby")
P2P._send_P2P_Packet(0,0, {"message": "handshake", "from": NetworkManager.STEAM_ID},Steam.P2P_SEND_RELIABLE)
func _on_p2p_session_request(remote_id: int) -> void:
# Get the requester's name
var this_requester: String = Steam.getFriendPersonaName(remote_id)
print("%s is requesting a P2P session" % this_requester)
# Accept the P2P session; can apply logic to deny this request if needed
Steam.acceptP2PSessionWithUser(remote_id)
# Make the initial handshake
make_p2p_handshake()
#endregion
#region LobbyEvents
func _on_p2p_session_connect_fail(lobby_id: int, session_error: int) -> void:
# Note the session errors are: 0 - none, 1 - target user not running the same game, 2 - local user doesn't own app, 3 - target user isn't connected to Steam, 4 - connection timed out, 5 - unused
# If no error was given
if session_error == 0:
print("[WARNING] Session failure with "+str(lobby_id)+" [no error given].")
# Else if target user was not running the same game
elif session_error == 1:
print("[WARNING] Session failure with "+str(lobby_id)+" [target user not running the same game].")
# Else if local user doesn't own app / game
elif session_error == 2:
print("[WARNING] Session failure with "+str(lobby_id)+" [local user doesn't own app / game].")
# Else if target user isn't connected to Steam
elif session_error == 3:
print("[WARNING] Session failure with "+str(lobby_id)+" [target user isn't connected to Steam].")
# Else if connection timed out
elif session_error == 4:
print("[WARNING] Session failure with "+str(lobby_id)+" [connection timed out].")
# Else if unused
elif session_error == 5:
print("[WARNING] Session failure with "+str(lobby_id)+" [unused].")
# Else no known error
else:
print("[WARNING] Session failure with "+str(lobby_id)+" [unknown error "+str(session_error)+"].")
func _on_lobby_chat_update(this_lobby_id: int, change_id: int, making_change_id: int, chat_state: int) -> void:
# Get the user who has made the lobby change
var changer_name: String = Steam.getFriendPersonaName(change_id)
# If a player has joined the lobby
if chat_state == Steam.CHAT_MEMBER_STATE_CHANGE_ENTERED:
print("%s has joined the lobby." % changer_name)
# Else if a player has left the lobby
elif chat_state == Steam.CHAT_MEMBER_STATE_CHANGE_LEFT:
print("%s has left the lobby." % changer_name)
# Else if a player has been kicked
elif chat_state == Steam.CHAT_MEMBER_STATE_CHANGE_KICKED:
print("%s has been kicked from the lobby." % changer_name)
# Else if a player has been banned
elif chat_state == Steam.CHAT_MEMBER_STATE_CHANGE_BANNED:
print("%s has been banned from the lobby." % changer_name)
# Else there was some unknown change
else:
print("%s did... something." % changer_name)
# Update the lobby now that a change has occurred
get_lobby_members()
#endregion
func _on_ready_btn_pressed():
if NetworkManager.STEAM_ID == Steam.getLobbyOwner(NetworkManager.LOBBY_ID):
im_ready = !im_ready
#for ready in NetworkManager.IS_READY.keys():
#if ready == NetworkManager.STEAM_ID:
NetworkManager.IS_READY[NetworkManager.STEAM_ID] = im_ready
else:
im_ready = !im_ready
P2P._send_P2P_Packet(0,Steam.getLobbyOwner(NetworkManager.LOBBY_ID),{"TYPE":NetworkManager.TYPES.READY,"steam_id":NetworkManager.STEAM_ID,"ready":im_ready},Steam.P2P_SEND_RELIABLE)
func _on_start_btn_pressed():
if NetworkManager.STEAM_ID == Steam.getLobbyOwner(NetworkManager.LOBBY_ID):
var result = NetworkManager.IS_READY.values().all(func(number): return number == true)
if result:
SceneManager.change_scene("res://godotsteam_sync_example/Test.tscn")

View File

@ -1,34 +0,0 @@
extends Panel
var STEAM_ID: int = 0
# Stored at the class level to enable comparisons when helper functions are called
var AVATAR: Image
# Is it ready? Do stuff!
func _ready():
# connect some signals
var SIGNAL_CONNECT: int = Steam.connect("avatar_loaded", Callable(self, "_loaded_Avatar"))
# Set this player up
func _set_Member(steam_id: int, steam_name: String) -> void:
# Set the ID and username
STEAM_ID = steam_id
$MarginContainer/HBoxContainer/ScrollContainer/UsernameLbl.set_text(steam_name)
# Get the avatar and show it
Steam.getPlayerAvatar(Steam.AVATAR_MEDIUM, STEAM_ID)
# Load an avatar
func _loaded_Avatar(id: int, this_size: int, buffer: PackedByteArray) -> void:
# Check we're only triggering a load for the right player, and check the data has actually changed
if id == STEAM_ID and (not AVATAR or not buffer == AVATAR.get_data()):
# Create the image and texture for loading
AVATAR = Image.create_from_data(this_size, this_size, false, Image.FORMAT_RGBA8, buffer)
# Apply it to the texture
var AVATAR_TEXTURE: ImageTexture = ImageTexture.create_from_image(AVATAR)
# Set it
$MarginContainer/HBoxContainer/Avatar.set_texture(AVATAR_TEXTURE)
func _on_view_btn_pressed():
Steam.activateGameOverlayToUser("steamid", STEAM_ID)

View File

@ -1,55 +0,0 @@
[gd_scene load_steps=3 format=3 uid="uid://d26bfvwtqaeqw"]
[ext_resource type="Script" path="res://addons/godot_steam_sync/Lobby/lobby_member.gd" id="1_vi8x1"]
[sub_resource type="LabelSettings" id="LabelSettings_x51ve"]
font_size = 10
[node name="LobbyMember" type="Panel"]
custom_minimum_size = Vector2(236, 36)
offset_right = 236.0
offset_bottom = 36.0
script = ExtResource("1_vi8x1")
metadata/_edit_use_anchors_ = true
[node name="MarginContainer" type="MarginContainer" parent="."]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
theme_override_constants/margin_left = 3
theme_override_constants/margin_top = 3
theme_override_constants/margin_right = 3
theme_override_constants/margin_bottom = 3
[node name="HBoxContainer" type="HBoxContainer" parent="MarginContainer"]
layout_mode = 2
[node name="Avatar" type="TextureRect" parent="MarginContainer/HBoxContainer"]
custom_minimum_size = Vector2(30, 30)
layout_mode = 2
expand_mode = 1
[node name="ScrollContainer" type="ScrollContainer" parent="MarginContainer/HBoxContainer"]
layout_mode = 2
size_flags_horizontal = 3
[node name="UsernameLbl" type="Label" parent="MarginContainer/HBoxContainer/ScrollContainer"]
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 3
text = "Space War Name"
label_settings = SubResource("LabelSettings_x51ve")
horizontal_alignment = 1
vertical_alignment = 1
[node name="ViewBtn" type="Button" parent="MarginContainer/HBoxContainer"]
custom_minimum_size = Vector2(30, 30)
layout_mode = 2
theme_override_colors/font_color = Color(0, 1, 0, 1)
theme_override_font_sizes/font_size = 14
text = "View"
[connection signal="pressed" from="MarginContainer/HBoxContainer/ViewBtn" to="." method="_on_view_btn_pressed"]

View File

@ -1,172 +0,0 @@
[gd_scene load_steps=2 format=3 uid="uid://cliutsom3dxmu"]
[ext_resource type="Script" path="res://addons/godot_steam_sync/Lobby/lobby.gd" id="1_2lhov"]
[node name="LobbyMenu" type="Control"]
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
script = ExtResource("1_2lhov")
[node name="Panel" type="Panel" parent="."]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
[node name="MembersPnl" type="Panel" parent="."]
visible = false
layout_mode = 1
anchors_preset = -1
anchor_left = 1.0
anchor_top = 1.0
anchor_right = 1.0
anchor_bottom = 1.0
offset_left = -276.0
offset_top = -262.0
offset_right = -10.0
offset_bottom = -12.0
grow_horizontal = 0
grow_vertical = 0
metadata/_edit_use_anchors_ = true
[node name="MarginContainer" type="MarginContainer" parent="MembersPnl"]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
theme_override_constants/margin_left = 5
theme_override_constants/margin_top = 5
theme_override_constants/margin_right = 5
theme_override_constants/margin_bottom = 5
[node name="ScrollContainer" type="ScrollContainer" parent="MembersPnl/MarginContainer"]
layout_mode = 2
[node name="VBoxContainer" type="VBoxContainer" parent="MembersPnl/MarginContainer/ScrollContainer"]
layout_mode = 2
alignment = 1
[node name="CreateLobbyCont" type="VBoxContainer" parent="."]
layout_mode = 1
anchors_preset = 8
anchor_left = 0.5
anchor_top = 0.5
anchor_right = 0.5
anchor_bottom = 0.5
offset_left = -143.0
offset_top = -162.0
offset_right = 143.0
offset_bottom = 162.0
grow_horizontal = 2
grow_vertical = 2
[node name="LobbyNameTxt" type="TextEdit" parent="CreateLobbyCont"]
custom_minimum_size = Vector2(0, 40)
layout_mode = 2
placeholder_text = "Lobby Name"
scroll_smooth = true
[node name="LobbyVisibilityBtn" type="OptionButton" parent="CreateLobbyCont"]
custom_minimum_size = Vector2(300, 35)
layout_mode = 2
selected = 2
item_count = 4
popup/item_0/text = "PRIVATE"
popup/item_1/text = "FRIENDS ONLY"
popup/item_1/id = 1
popup/item_2/text = "PUBLIC"
popup/item_2/id = 2
popup/item_3/text = "INVISIBLE"
popup/item_3/id = 3
[node name="MaxMembersBtn" type="OptionButton" parent="CreateLobbyCont"]
custom_minimum_size = Vector2(300, 35)
layout_mode = 2
selected = 1
item_count = 4
popup/item_0/text = "2"
popup/item_1/text = "4"
popup/item_1/id = 1
popup/item_2/text = "8"
popup/item_2/id = 2
popup/item_3/text = "16"
popup/item_3/id = 3
[node name="CreateLobbyBtn" type="Button" parent="CreateLobbyCont"]
custom_minimum_size = Vector2(0, 70)
layout_mode = 2
text = "Create Lobby"
[node name="LobbyPanel" type="Panel" parent="."]
visible = false
layout_mode = 1
anchors_preset = 8
anchor_left = 0.5
anchor_top = 0.5
anchor_right = 0.5
anchor_bottom = 0.5
offset_left = -171.0
offset_top = -148.0
offset_right = 171.0
offset_bottom = 172.0
grow_horizontal = 2
grow_vertical = 2
[node name="MarginContainer" type="MarginContainer" parent="LobbyPanel"]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
theme_override_constants/margin_left = 10
theme_override_constants/margin_top = 10
theme_override_constants/margin_right = 10
theme_override_constants/margin_bottom = 10
[node name="LobbyCont" type="VBoxContainer" parent="LobbyPanel/MarginContainer"]
layout_mode = 2
[node name="Panel" type="Panel" parent="LobbyPanel/MarginContainer/LobbyCont"]
custom_minimum_size = Vector2(0, 60)
layout_mode = 2
[node name="LobbyNameLbl" type="Label" parent="LobbyPanel/MarginContainer/LobbyCont/Panel"]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
theme_override_font_sizes/font_size = 27
text = "Lobby Name"
horizontal_alignment = 1
vertical_alignment = 1
[node name="Space" type="Control" parent="LobbyPanel/MarginContainer/LobbyCont"]
custom_minimum_size = Vector2(0, 55.06)
layout_mode = 2
[node name="ReadyBtn" type="Button" parent="LobbyPanel/MarginContainer/LobbyCont"]
custom_minimum_size = Vector2(0, 80)
layout_mode = 2
theme_override_font_sizes/font_size = 33
text = "READY"
[node name="StartBtn" type="Button" parent="LobbyPanel/MarginContainer/LobbyCont"]
custom_minimum_size = Vector2(0, 80)
layout_mode = 2
theme_override_font_sizes/font_size = 33
text = "Start"
[connection signal="pressed" from="CreateLobbyCont/CreateLobbyBtn" to="." method="_on_create_lobby_btn_pressed"]
[connection signal="pressed" from="LobbyPanel/MarginContainer/LobbyCont/ReadyBtn" to="." method="_on_ready_btn_pressed"]
[connection signal="pressed" from="LobbyPanel/MarginContainer/LobbyCont/StartBtn" to="." method="_on_start_btn_pressed"]

View File

@ -1,24 +0,0 @@
extends Control
@onready var online_text = $OnlineLbl
func _ready():
if NetworkManager.IS_ONLINE:
online_text.text = "online"
else:
online_text.text = "offline"
func _on_play_btn_pressed():
get_tree().change_scene_to_file("res://addons/godot_steam_sync/Lobby/lobby_menu.tscn")
func _on_exit_btn_pressed():
get_tree().quit()

View File

@ -1,83 +0,0 @@
[gd_scene load_steps=3 format=3 uid="uid://1d2bxfqc4m8x"]
[ext_resource type="Script" path="res://addons/godot_steam_sync/Lobby/main_menu.gd" id="1_6wvtt"]
[sub_resource type="SystemFont" id="SystemFont_j72ml"]
font_names = PackedStringArray("Sylfaen")
[node name="MainMenu" type="Control"]
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
script = ExtResource("1_6wvtt")
[node name="Panel" type="Panel" parent="."]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
[node name="OnlineLbl" type="Label" parent="."]
layout_mode = 1
anchors_preset = 3
anchor_left = 1.0
anchor_top = 1.0
anchor_right = 1.0
anchor_bottom = 1.0
offset_left = -49.0
offset_top = -23.0
grow_horizontal = 0
grow_vertical = 0
theme_override_font_sizes/font_size = 0
text = "online"
[node name="VBoxContainer" type="VBoxContainer" parent="."]
layout_mode = 1
anchors_preset = 8
anchor_left = 0.5
anchor_top = 0.5
anchor_right = 0.5
anchor_bottom = 0.5
offset_left = -175.0
offset_top = -35.0
offset_right = 175.0
offset_bottom = 35.0
grow_horizontal = 2
grow_vertical = 2
[node name="PlayBtn" type="Button" parent="VBoxContainer"]
custom_minimum_size = Vector2(350, 70)
layout_mode = 2
text = "Play Online
"
[node name="ExitBtn" type="Button" parent="VBoxContainer"]
custom_minimum_size = Vector2(350, 70)
layout_mode = 2
text = "Quit"
[node name="Titel" type="Label" parent="."]
layout_mode = 1
anchors_preset = 8
anchor_left = 0.5
anchor_top = 0.5
anchor_right = 0.5
anchor_bottom = 0.5
offset_left = -277.0
offset_top = -201.0
offset_right = 277.0
offset_bottom = -143.0
grow_horizontal = 2
grow_vertical = 2
theme_override_fonts/font = SubResource("SystemFont_j72ml")
theme_override_font_sizes/font_size = 56
text = "GODOT STEAM SYNC"
uppercase = true
[connection signal="pressed" from="VBoxContainer/PlayBtn" to="." method="_on_play_btn_pressed"]
[connection signal="pressed" from="VBoxContainer/ExitBtn" to="." method="_on_exit_btn_pressed"]

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.3 KiB

View File

@ -1,34 +0,0 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://ctruhwnscx144"
path="res://.godot/imported/2.png-252d97d15980179767bc6bbd64608b77.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://addons/godot_steam_sync/Media/2.png"
dest_files=["res://.godot/imported/2.png-252d97d15980179767bc6bbd64608b77.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

View File

@ -1,34 +0,0 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://bbbywy0ofvkhx"
path="res://.godot/imported/image.png-c17ce491b4f523d51f56704d6387b67a.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://addons/godot_steam_sync/Media/image.png"
dest_files=["res://.godot/imported/image.png-c17ce491b4f523d51f56704d6387b67a.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

View File

@ -1,55 +0,0 @@
extends Node
var IS_ON_STEAM: bool = false
var IS_ON_STEAM_DECK: bool = false
var IS_ONLINE: bool = false
var IS_OWNED: bool = false
var STEAM_ID: int = 0
var STEAM_USERNAME: String = "No one"
var LOBBY_ID: int = 0
var LOBBY_MEMBERS: Array = []
var DATA : Dictionary
var LOBBY_MAX_MEMBERS: int = 4
var GAME_STARTED : bool = false
var IS_READY : Dictionary = {}
enum TYPES {START,READY,START_SCENE,TRANFORM_SYNC,PROPERTY,EVENT,RIGIDBODY_SYNC,SCENE_LOADED,COMMAND,VOICE,RAGDOLL,CHANGE_SCENE}
@onready var player = preload("res://godotsteam_sync_example/fpc/character.tscn")
#region Initilazation
func _ready() -> void:
_initialize_Steam()
if IS_ON_STEAM_DECK:
get_window().mode = Window.MODE_EXCLUSIVE_FULLSCREEN
func _initialize_Steam() -> void:
if Engine.has_singleton("Steam"):
var INIT: Dictionary = Steam.steamInitEx(true,480)
# If the status isn't one, print out the possible error and quit the program
if INIT['status'] != 0:
print("[STEAM] Failed to initialize: "+str(INIT)+" Shutting down...")
get_tree().quit()
# Is the user actually using Steam; if false, the app assumes this is a non-Steam version
IS_ON_STEAM = true
# Checking if the app is on Steam Deck to modify certain behaviors
IS_ON_STEAM_DECK = Steam.isSteamRunningOnSteamDeck()
# Acquire information about the user
IS_ONLINE = Steam.loggedOn()
IS_OWNED = Steam.isSubscribed()
STEAM_ID = Steam.getSteamID()
STEAM_USERNAME = Steam.getPersonaName()
# Check if account owns the game
if IS_OWNED == false:
print("[STEAM] User does not own this game")
# Uncomment this line to close the game if the user does not own the game
get_tree().quit()
func _process(_delta: float) -> void:
if IS_ON_STEAM:
Steam.run_callbacks()
#endregion

View File

@ -1,85 +0,0 @@
class_name NetworkPlayerSpawner extends Node
## Where the players will be spawned.
@export var spawn_pos : Node
## The node the players will be in after they are spawned. It has to be at the center of the scene. It has to be named 'Players'.
@export var players_parent_node : Node
## Here you can choose which way each spawned player will move. If you choose an axis, the player born will automatically move one unit away. If the game is 2D, choosing the Z axis means the center.
@export_flags("X" ,"Y" ,"Z") var spawn_distance_axis = 1
@export var increase_spawn_distance : Vector3
func _ready():
players_parent_node.name = "Players"
if spawn_pos is Node3D:
for player in NetworkManager.LOBBY_MEMBERS.size():
var instance_player : Node = NetworkManager.player.instantiate()
instance_player.name = str(NetworkManager.LOBBY_MEMBERS[player]["steam_id"])
var direction = spawn_check()
match direction:
"CENTER":
instance_player.transform.origin = spawn_pos.transform.origin + Vector3(0, 0, 0)
"X":
instance_player.transform.origin = spawn_pos.transform.origin + Vector3(player + increase_spawn_distance.x, 0, 0)
"Y":
instance_player.transform.origin = spawn_pos.transform.origin + Vector3(0, player + increase_spawn_distance.y, 0)
"Z":
instance_player.transform.origin = spawn_pos.transform.origin + Vector3(0, 0, player + increase_spawn_distance.z)
"XY":
instance_player.transform.origin = spawn_pos.transform.origin + Vector3(player + increase_spawn_distance.x, player + increase_spawn_distance.y, 0)
"XZ":
instance_player.transform.origin = spawn_pos.transform.origin + Vector3(player + increase_spawn_distance.x, 0, player + increase_spawn_distance.z)
"YZ":
instance_player.transform.origin = spawn_pos.transform.origin + Vector3(0, player + increase_spawn_distance.y, player + increase_spawn_distance.z)
"XYZ":
instance_player.transform.origin = spawn_pos.transform.origin + Vector3(player + increase_spawn_distance.x, player + increase_spawn_distance.y, player + increase_spawn_distance.z)
_:
instance_player.transform.origin = spawn_pos.transform.origin + Vector3(0, 0, 0)
players_parent_node.add_child(instance_player)
if instance_player.name == str(NetworkManager.STEAM_ID):
instance_player.make_owner()
NetworkManager.GAME_STARTED = true
if spawn_pos is Node2D:
for player in NetworkManager.LOBBY_MEMBERS.size():
var instance_player : Node = NetworkManager.player.instantiate()
instance_player.name = str(NetworkManager.LOBBY_MEMBERS[player]["steam_id"])
var direction = spawn_check()
match direction:
"CENTER":
instance_player.position = spawn_pos.position + Vector2(0, 0)
"X":
instance_player.position = spawn_pos.position + Vector2(player + increase_spawn_distance.x, 0)
"Y":
instance_player.position = spawn_pos.position + Vector2(0, player + increase_spawn_distance.y)
"XY":
instance_player.position = spawn_pos.position + Vector2(player + increase_spawn_distance.x, player + increase_spawn_distance.y)
_:
instance_player.position = spawn_pos.position + Vector2(0, 0)
players_parent_node.add_child(instance_player)
if instance_player.name == str(NetworkManager.STEAM_ID):
instance_player.make_owner()
NetworkManager.GAME_STARTED = true
func spawn_check() -> String:
match spawn_distance_axis:
0:
return "CENTER"
1:
return "X"
2:
return "Y"
3:
return "XY"
4:
return "Z"
5:
return "XZ"
6:
return "YZ"
7:
return "XYZ"
_:
return "CENTER"
return "CENTER"

View File

@ -1,134 +0,0 @@
extends Node
const PACKET_READ_LIMIT: int = 32
func _process(_delta: float) -> void:
# Get packets only if lobby is joined
if NetworkManager.LOBBY_ID > 0:
_read_All_P2P_Packets()
func _read_P2P_Packet() -> void:
var packet_size0 : int = Steam.getAvailableP2PPacketSize(0)
#region Channel0
if packet_size0 > 0:
var this_packet0 : Dictionary = Steam.readP2PPacket(packet_size0, 0)
if this_packet0.is_empty() or this_packet0 == null:
print("WARNING: read an empty packet with non-zero size!")
# Get the remote user's ID
var packet_sender: int = this_packet0['remote_steam_id']
# Make the packet data readablev
var packet_code: PackedByteArray = this_packet0['data']
# Decompress the array before turning it into a useable dictionary
var READABLE: Dictionary = bytes_to_var(packet_code.decompress_dynamic(-1, FileAccess.COMPRESSION_GZIP))
# Append logic here to deal with packet data
if READABLE.has("TYPE"):
handle_packets(READABLE)
#endregion
func _read_All_P2P_Packets(read_count: int = 0) -> void:
if read_count >= PACKET_READ_LIMIT:
return
if Steam.getAvailableP2PPacketSize(0) > 0:
_read_P2P_Packet()
_read_All_P2P_Packets(read_count + 1)
var packet_size : float
func _send_P2P_Packet(channel: int,target: int, packet_data: Dictionary,send_type: int) -> bool:
# Create a data array to send the data through
var this_data: PackedByteArray
# Compress the PackedByteArray we create from our dictionary using the GZIP compression method
var compressed_data: PackedByteArray = var_to_bytes(packet_data).compress(FileAccess.COMPRESSION_GZIP)
this_data.append_array(compressed_data)
packet_size = this_data.size()
# If sending a packet to everyone
if target == 0:
# If there is more than one user, send packets
if NetworkManager.LOBBY_MEMBERS.size() > 1:
# Loop through all members that aren't you
for this_member in NetworkManager.LOBBY_MEMBERS:
if this_member['steam_id'] != NetworkManager.STEAM_ID:
return Steam.sendP2PPacket(this_member['steam_id'], this_data, send_type, channel)
else:
return Steam.sendP2PPacket(target, this_data, send_type, channel)
return false
func handle_start_packet(READABLE):
# This packet reading when someone ready
if READABLE["TYPE"] == NetworkManager.TYPES.READY:
NetworkManager.IS_READY[READABLE["steam_id"]] = READABLE["ready"]
SceneManager.change_scene("res://godotsteam_sync_example/Test.tscn")
# This packet reading when lobby leader change_scene
#if READABLE["TYPE"] == NetworkManager.TYPES.START_SCENE:
#SceneManager.change_scene(READABLE["scene"])
#
func handle_event_packets(READABLE):
#if READABLE["TYPE"] == NetworkManager.TYPES.COMMAND:
#print("COMMAND:" + READABLE["method"] + str(READABLE["args"]))
#if READABLE["args"] != null:
#Command.callv(READABLE["method"],READABLE["args"])
#else:
#Command.call(READABLE["method"])
if READABLE['TYPE'] == NetworkManager.TYPES.EVENT:
if READABLE["args"] != null:
get_tree().root.get_node(READABLE["node_path"]).callv(READABLE["method"],READABLE["args"])
else:
get_tree().root.get_node(READABLE["node_path"]).call(READABLE["method"])
if READABLE["TYPE"] == NetworkManager.TYPES.SCENE_LOADED:
handle_scene_change(READABLE)
func handle_property_packets(READABLE):
if READABLE['TYPE'] == NetworkManager.TYPES.TRANFORM_SYNC and NetworkManager.GAME_STARTED:
if READABLE["property"] == "global_position":
get_tree().root.get_node(READABLE["node_path"]).transform_buffer[0] = READABLE
if READABLE["property"] == "rotation":
get_tree().root.get_node(READABLE["node_path"]).transform_buffer[1] = READABLE
if READABLE["property"] == "scale":
get_tree().root.get_node(READABLE["node_path"]).transform_buffer[2] = READABLE
if READABLE["TYPE"] == NetworkManager.TYPES.RAGDOLL and NetworkManager.GAME_STARTED:
get_tree().root.get_node(READABLE["node_path"]).transform_buffer = READABLE
if READABLE["TYPE"] == NetworkManager.TYPES.RIGIDBODY_SYNC and NetworkManager.GAME_STARTED:
get_tree().root.get_node(READABLE["node_path"]).sync_data = READABLE
if READABLE["TYPE"] == NetworkManager.TYPES.PROPERTY and NetworkManager.GAME_STARTED:
if !READABLE["interpolated"]:
get_tree().root.get_node(READABLE["node_path"]).set(READABLE["property"],READABLE["value"])
else:
var DATA :Array = [READABLE["property"],READABLE["value"]]
get_tree().root.get_node(READABLE["node_path"]).DATA = DATA
func handle_voice(READABLE):
if READABLE["TYPE"] == NetworkManager.TYPES.VOICE and NetworkManager.GAME_STARTED:
get_tree().root.get_node(READABLE["node_path"]).process_voice_data(READABLE["voice_data"])
#await get_tree().create_timer(0.1).timeout
func handle_scene_change(READABLE):
get_tree().change_scene_to_file(READABLE["scene"])
func handle_packets(READABLE):
handle_start_packet(READABLE)
handle_event_packets(READABLE)
handle_property_packets(READABLE)
handle_voice(READABLE)

View File

@ -1,14 +0,0 @@
extends Node
#@onready var loadingScreen = preload("res://addons/godot_steam_sync/SceneChanger/LoadingScreen.tscn")
#func send(method : String,args = null):
#var DATA : Dictionary = {"player_id":NetworkManager.STEAM_ID,"TYPE":NetworkManager.TYPES.COMMAND,"args":args,"method":method}
#P2P._send_P2P_Packet(0,0, DATA,Steam.P2P_SEND_RELIABLE)
#
#
#func start_scene(scene : String):
#NetworkManager.GAME_STARTED = false
#var instance = loadingScreen.instantiate()
#get_parent().add_child(instance)
#instance.change(scene)
#

View File

@ -1,15 +0,0 @@
@icon("res://addons/godot_steam_sync/Network/RadomeSteamSync/SyncNode/funcSyncIcon.png")
class_name FuncSync extends Synchronizer
signal FuncCalled(method : String,args)
func _ready() -> void:
connect("FuncCalled",_on_func_called)
func call_f(method : String,args = null):
emit_signal("FuncCalled",method,args)
func _on_func_called(method, args):
if NetworkManager.GAME_STARTED:
var DATA : Dictionary = {"player_id":NetworkManager.STEAM_ID,"TYPE":NetworkManager.TYPES.EVENT,"args":args,"node_path":get_parent().get_path(),"method":method}
P2P._send_P2P_Packet(0,0, DATA,Steam.P2P_SEND_RELIABLE)

View File

@ -1,71 +0,0 @@
@icon("res://addons/godot_steam_sync/Network/RadomeSteamSync/SyncNode/propertySyncIcon.png")
class_name PropertySync extends Synchronizer
@export_group("SETTINGS","is")
## If true, onlu lobby owner will send the packet.
@export var is_only_lobby_owner : bool = false
@export_group("NODES","object")
## Select player if its not player or not inside player you can make 'is_only_lobby_owner' true.
@export var object_player : Node
@export_group("INTERPOLATION")
@export var is_interpolated :bool = false
@export var interpolation_value : float = 0.1
@export_group("")
@export var property_list : PackedStringArray## Hangi ozellikler yollayacaksak
var property_type : Array
var DATA : Array
var path : NodePath
var timer : Timer
func init_timer():
timer = Timer.new()
timer.process_callback = Timer.TIMER_PROCESS_PHYSICS
timer.wait_time = 0.1
add_child(timer)
timer.autostart = true
timer.start()
timer.connect("timeout",_on_timer_timeout)
func _ready():
init_timer()
if !is_interpolated:
path = get_parent().get_path()
set_process(false)
else:
path = get_path()
if is_only_lobby_owner == false and object_player.name != str(NetworkManager.STEAM_ID):
timer.stop()
elif is_only_lobby_owner:
if Steam.getLobbyOwner(NetworkManager.LOBBY_ID) != NetworkManager.STEAM_ID:
timer.stop()
for property in property_list:
var v = get_parent().get(property)
property_type.append(v)
func _process(delta):
# Data[0] property Data[1] value
if (!DATA.is_empty()):
get_parent().set(DATA[0],lerp(get_parent().get(DATA[0]),DATA[1],interpolation_value))
func _on_timer_timeout():
for property in property_list.size():
if property_type[property] != get_parent().get(property_list[property]) and NetworkManager.GAME_STARTED:
var DATA : Dictionary = {"player_id":NetworkManager.STEAM_ID,"TYPE":NetworkManager.TYPES.PROPERTY,"value":get_parent().get(property_list[property]),"node_path":path,"property":property_list[property],"interpolated":is_interpolated}
P2P._send_P2P_Packet(0,0, DATA,Steam.P2P_SEND_RELIABLE)
property_type[property] = get_parent().get(property_list[property])
func abort():
timer.stop()
set_process(false)

View File

@ -1,76 +0,0 @@
@icon("res://Network/RadomeSteamSync/SyncNode/transformSyncIcon.png")
class_name RagDollSync extends Synchronizer
@export_group("SETTINGS","is")
## If true, onlu lobby owner will send the packet.
@export var is_only_lobby_owner : bool = false
@export_group("NODES","object")
## Select player if its not player or not inside player you can make 'is_only_lobby_owner' true.
@export var object_player : Node
@export var interpolation : float = 0.35
signal simulating(status : bool)
var bones : Array[PhysicalBone3D]
var packet_index_pos : int = 0
var last_pos : Array[Vector3]
var transform_buffer : Dictionary = {}
var last_index_buffer : int
var timer : Timer
func init_timer():
timer = Timer.new()
timer.process_callback = Timer.TIMER_PROCESS_PHYSICS
timer.wait_time = 0.1
add_child(timer)
timer.connect("timeout",_on_pos_timer_timeout)
func _ready():
init_timer()
get_all_bones()
func get_pos_bone() -> Array[Vector3]:
var pos : Array[Vector3]
for bone in bones:
pos.append(bone.global_transform.origin)
return pos
func get_all_bones():
for i in get_parent().get_children():
if is_instance_of(i,PhysicalBone3D):
bones.append(i)
func _on_pos_timer_timeout():
if get_pos_bone() != last_pos and NetworkManager.GAME_STARTED:
var pos = get_pos_bone()
var DATA : Dictionary = {"Idx":packet_index_pos + 1,"TYPE":NetworkManager.TYPES.RAGDOLL,"value":pos,"node_path":get_path()}
P2P._send_P2P_Packet(0,0, DATA,Steam.P2P_SEND_UNRELIABLE)
packet_index_pos = packet_index_pos + 1
last_pos = pos
func _physics_process(delta):
if transform_buffer.has("Idx") and NetworkManager.GAME_STARTED:
if transform_buffer["Idx"] >= last_index_buffer :
set_pos_bone(transform_buffer["value"])
func set_pos_bone(DATA):
for i in range(bones.size()):
var lerped_value = lerp(bones[i].global_transform.origin,DATA[i],interpolation)
bones[i].global_transform.origin = lerped_value
last_index_buffer = transform_buffer["Idx"]
func abort():
set_process(false)
timer.stop()
func _on_simulating(status : bool):
if status== true:
if is_only_lobby_owner and Steam.getLobbyOwner(NetworkManager.LOBBY_ID) == NetworkManager.STEAM_ID:
timer.start()
elif !is_only_lobby_owner and str(NetworkManager.STEAM_ID) == object_player.name:
timer.start()
else:
timer.stop()

View File

@ -1,50 +0,0 @@
class_name RigidBodySync2D extends Synchronizer
@export var interpolation_value = 0.3
var packet_index: int = 0
var state_data = null
var last_index : int = 0
var last_pos : Vector3 = Vector3.ZERO
var pTimer : Timer
func init_timer():
pTimer = Timer.new()
pTimer.process_callback = Timer.TIMER_PROCESS_PHYSICS
pTimer.wait_time = 1.0 / 30.0
add_child(pTimer)
pTimer.autostart = true
pTimer.start()
pTimer.connect("timeout",_on_timeout)
func _ready():
init_timer()
if Steam.getLobbyOwner(NetworkManager.LOBBY_ID) != NetworkManager.STEAM_ID:
pTimer.stop()
func _on_timeout():
if get_parent().position != last_pos and NetworkManager.GAME_STARTED:
var DATA : Dictionary = {"Idx":packet_index,"player_id":NetworkManager.STEAM_ID,"TYPE":NetworkManager.TYPES.RIGIDBODY_SYNC,"value":get_parent().linear_velocity,"node_path":get_path(),}
P2P._send_P2P_Packet(0,0, DATA,Steam.P2P_SEND_UNRELIABLE)
packet_index = packet_index + 1
last_pos = get_parent().linear_velocity
func update_physics_values():
var target_linear_velocity = state_data["value"][0]
var target_angular_velocity = state_data["value"][1]
var target_position = state_data["value"][2]
var target_rotation = state_data["value"][3]
# Linear velocity için Lerp
get_parent().linear_velocity = lerp(get_parent().linear_velocity, target_linear_velocity, interpolation_value)
# Angular velocity için Lerp
get_parent().angular_velocity = lerp(get_parent().angular_velocity, target_angular_velocity, interpolation_value)
# Position için Lerp
get_parent().position = lerp(get_parent().position, target_position, interpolation_value)
# Rotation için Lerp (Quaternion için)
get_parent().rotation = lerp(get_parent().rotation , target_rotation, interpolation_value)
func _physics_process(delta: float) -> void:
if state_data != null and NetworkManager.GAME_STARTED:
if state_data["Idx"] >= last_index :
update_physics_values()
last_index = state_data["Idx"]

View File

@ -1,54 +0,0 @@
class_name RigidBodySync3D extends Synchronizer
@export var interpolation_value = 0.3
var packet_index: int = 0
var state_data = null
var last_index : int = 0
var last_pos : Vector3 = Vector3.ZERO
var pTimer : Timer
func init_timer():
pTimer = Timer.new()
pTimer.process_callback = Timer.TIMER_PROCESS_PHYSICS
pTimer.wait_time = 1.0 /30.0
add_child(pTimer)
pTimer.autostart = true
pTimer.start()
pTimer.connect("timeout",_on_timer_timeout)
func _ready():
init_timer()
if Steam.getLobbyOwner(NetworkManager.LOBBY_ID) != NetworkManager.STEAM_ID:
pTimer.stop()
func _on_timer_timeout():
if get_parent().position != last_pos and NetworkManager.GAME_STARTED:
var DATA : Dictionary = {"Idx":packet_index,"player_id":NetworkManager.STEAM_ID,"TYPE":NetworkManager.TYPES.RIGIDBODY_SYNC,"value":[get_parent().linear_velocity,get_parent().angular_velocity,get_parent().position,get_parent().rotation],"node_path":get_path()}
P2P._send_P2P_Packet(0,0, DATA,Steam.P2P_SEND_UNRELIABLE)
packet_index = packet_index + 1
last_pos = get_parent().position
func update_physics_values():
var target_linear_velocity = state_data["value"][0]
var target_angular_velocity = state_data["value"][1]
var target_position = state_data["value"][2]
var target_rotation = state_data["value"][3]
# Linear velocity için Lerp
get_parent().linear_velocity = lerp(get_parent().linear_velocity, target_linear_velocity, interpolation_value)
# Angular velocity için Lerp
get_parent().angular_velocity = lerp(get_parent().angular_velocity, target_angular_velocity, interpolation_value)
# Position için Lerp
get_parent().position = lerp(get_parent().position, target_position, interpolation_value)
# Rotation için Lerp (Quaternion için)
get_parent().rotation = lerp(get_parent().rotation , target_rotation, interpolation_value)
func _physics_process(delta: float) -> void:
await get_tree().create_timer(0.1).timeout
if state_data != null and NetworkManager.GAME_STARTED:
if state_data["Idx"] >= last_index :
update_physics_values()
last_index = state_data["Idx"]

View File

@ -1 +0,0 @@
class_name Synchronizer extends Node

View File

@ -1,127 +0,0 @@
@icon("res://addons/godot_steam_sync/Network/RadomeSteamSync/SyncNode/transformSyncIcon.png")
class_name TransformSync2D extends Synchronizer
@export_group("SETTINGS","is")
## If true, onlu lobby owner will send the packet.
@export var is_only_lobby_owner : bool = false
@export_group("NODES","object")
## Select player if its not player or not inside player you can make 'is_only_lobby_owner' true.
@export var object_player : Node
@export_group("")
@export var Position : bool = true
@export var Rotation : bool = false
@export var Scale : bool = false
var packet_index_pos : int = 0
var packet_index_rot : int = 0
var packet_index_scale : int = 0
var last_pos : Vector2 = Vector2.ZERO
var last_rot : float = 0
var last_scale : Vector2 = Vector2.ZERO
var transform_buffer : Array = [null,null,null]
var last_index_buffer : PackedInt32Array = [0,0,0]
var posTimer : Timer
var rotTimer : Timer
var sclTimer : Timer
func init_pos_timer():
posTimer = Timer.new()
posTimer.process_callback = Timer.TIMER_PROCESS_PHYSICS
posTimer.wait_time = 0.1
add_child(posTimer)
posTimer.autostart = true
posTimer.start()
posTimer.connect("timeout",_on_pos_timer_timeout)
func init_rot_timer():
rotTimer = Timer.new()
rotTimer.process_callback = Timer.TIMER_PROCESS_PHYSICS
rotTimer.wait_time = 0.1
add_child(rotTimer)
rotTimer.autostart = true
rotTimer.start()
rotTimer.connect("timeout",_on_rot_timer_timeout)
func init_scl_timer():
sclTimer = Timer.new()
sclTimer.process_callback = Timer.TIMER_PROCESS_PHYSICS
sclTimer.wait_time = 0.1
add_child(sclTimer)
sclTimer.autostart = true
sclTimer.start()
sclTimer.connect("timeout",_on_scale_timer_timeout)
func _ready():
init_pos_timer()
init_rot_timer()
init_scl_timer()
if is_only_lobby_owner == false and object_player.name != str(NetworkManager.STEAM_ID):
posTimer.stop()
rotTimer.stop()
sclTimer.stop()
elif is_only_lobby_owner:
if Steam.getLobbyOwner(NetworkManager.LOBBY_ID) != NetworkManager.STEAM_ID:
posTimer.stop()
rotTimer.stop()
sclTimer.stop()
if !Position:
posTimer.stop()
if !Rotation:
rotTimer.stop()
if !Scale:
sclTimer.stop()
func _on_pos_timer_timeout():
if get_parent().global_position != last_pos and NetworkManager.GAME_STARTED:
var DATA : Dictionary = {"Idx":packet_index_pos + 1,"player_id":NetworkManager.STEAM_ID,"TYPE":NetworkManager.TYPES.TRANFORM_SYNC,"value":get_parent().global_position,"node_path":get_path(),"property":"global_position"}
P2P._send_P2P_Packet(0,0, DATA,Steam.P2P_SEND_UNRELIABLE)
packet_index_pos = packet_index_pos + 1
last_pos = get_parent().global_position
func _on_rot_timer_timeout():
if get_parent().rotation != last_rot and NetworkManager.GAME_STARTED:
var DATA : Dictionary = {"Idx":packet_index_rot + 1,"player_id":NetworkManager.STEAM_ID,"TYPE":NetworkManager.TYPES.TRANFORM_SYNC,"value":get_parent().rotation,"node_path":get_path(),"property":"rotation"}
P2P._send_P2P_Packet(0,0, DATA,Steam.P2P_SEND_UNRELIABLE)
packet_index_rot = packet_index_rot + 1
last_rot = get_parent().rotation
func _on_scale_timer_timeout():
if get_parent().scale != last_scale and NetworkManager.GAME_STARTED:
var DATA : Dictionary = {"Idx":packet_index_scale + 1,"player_id":NetworkManager.STEAM_ID,"TYPE":NetworkManager.TYPES.TRANFORM_SYNC,"value":get_parent().scale,"node_path":get_path(),"property":"scale"}
P2P._send_P2P_Packet(0,0, DATA,Steam.P2P_SEND_UNRELIABLE)
packet_index_scale = packet_index_scale + 1
last_scale = get_parent().scale
func _process(delta):
if transform_buffer[0] != null and NetworkManager.GAME_STARTED:
if transform_buffer[0]["Idx"] >= last_index_buffer[0] :
var lerped_value = lerp(get_parent().get(transform_buffer[0]["property"]),transform_buffer[0]["value"],0.1)
get_parent().set(transform_buffer[0]["property"],lerped_value)
last_index_buffer[0] = transform_buffer[0]["Idx"]
# Rotation
if transform_buffer[1] != null and NetworkManager.GAME_STARTED:
if transform_buffer[1]["Idx"] >= last_index_buffer[1]:
var lerped_value = lerp(get_parent().get(transform_buffer[1]["property"]),transform_buffer[1]["value"],0.1)
get_parent().set(transform_buffer[1]["property"],lerped_value)
last_index_buffer[1] = transform_buffer[1]["Idx"]
# Scale
if transform_buffer[2] != null and NetworkManager.GAME_STARTED:
if transform_buffer[2]["Idx"] >= last_index_buffer[2]:
var lerped_value = lerp(get_parent().get(transform_buffer[2]["property"]),transform_buffer[2]["value"],0.1)
get_parent().set(transform_buffer[2]["property"],lerped_value)
last_index_buffer[2] = transform_buffer[2]["Idx"]
func abort():
posTimer.stop()
rotTimer.stop()
sclTimer.stop()
set_process(false)

View File

@ -1,126 +0,0 @@
@icon("res://addons/godot_steam_sync/Network/RadomeSteamSync/SyncNode/transformSyncIcon.png")
class_name TransformSync3D extends Synchronizer
@export_group("SETTINGS","is")
## If true, onlu lobby owner will send the packet.
@export var is_only_lobby_owner : bool = false
@export_group("NODES","object")
@export var object_player : Node ## Select player if its not player or not inside player you can make 'is_only_lobby_owner' true.
@export_group("")
@export var Position : bool = true
@export var Rotation : bool = false
@export var Scale : bool = false
var packet_index_pos : int = 0
var packet_index_rot : int = 0
var packet_index_scale : int = 0
var last_pos : Vector3 = Vector3.ZERO
var last_rot : Vector3 = Vector3.ZERO
var last_scale : Vector3 = Vector3.ZERO
var transform_buffer : Array = [null,null,null]
var last_index_buffer : PackedInt32Array = [0,0,0]
var posTimer : Timer
var rotTimer : Timer
var sclTimer : Timer
func init_pos_timer():
posTimer = Timer.new()
posTimer.process_callback = Timer.TIMER_PROCESS_PHYSICS
posTimer.wait_time = 0.1
add_child(posTimer)
posTimer.autostart = true
posTimer.start()
posTimer.connect("timeout",_on_pos_timer_timeout)
func init_rot_timer():
rotTimer = Timer.new()
rotTimer.process_callback = Timer.TIMER_PROCESS_PHYSICS
rotTimer.wait_time = 0.1
add_child(rotTimer)
rotTimer.autostart = true
rotTimer.start()
rotTimer.connect("timeout",_on_rot_timer_timeout)
func init_scl_timer():
sclTimer = Timer.new()
sclTimer.process_callback = Timer.TIMER_PROCESS_PHYSICS
sclTimer.wait_time = 0.1
add_child(sclTimer)
sclTimer.autostart = true
sclTimer.start()
sclTimer.connect("timeout",_on_scale_timer_timeout)
func _ready():
init_pos_timer()
init_rot_timer()
init_scl_timer()
if is_only_lobby_owner == false and object_player.name != str(NetworkManager.STEAM_ID):
posTimer.stop()
rotTimer.stop()
sclTimer.stop()
elif is_only_lobby_owner:
if Steam.getLobbyOwner(NetworkManager.LOBBY_ID) != NetworkManager.STEAM_ID:
posTimer.stop()
rotTimer.stop()
sclTimer.stop()
if !Position:
posTimer.stop()
if !Rotation:
rotTimer.stop()
if !Scale:
sclTimer.stop()
func _on_pos_timer_timeout():
if get_parent().global_position != last_pos and NetworkManager.GAME_STARTED:
var DATA : Dictionary = {"Idx":packet_index_pos + 1,"player_id":NetworkManager.STEAM_ID,"TYPE":NetworkManager.TYPES.TRANFORM_SYNC,"value":get_parent().global_position,"node_path":get_path(),"property":"global_position"}
P2P._send_P2P_Packet(0,0, DATA,Steam.P2P_SEND_UNRELIABLE)
packet_index_pos = packet_index_pos + 1
last_pos = get_parent().global_position
func _on_rot_timer_timeout():
if get_parent().rotation != last_rot and NetworkManager.GAME_STARTED:
var DATA : Dictionary = {"Idx":packet_index_rot + 1,"player_id":NetworkManager.STEAM_ID,"TYPE":NetworkManager.TYPES.TRANFORM_SYNC,"value":get_parent().rotation,"node_path":get_path(),"property":"rotation"}
P2P._send_P2P_Packet(0,0, DATA,Steam.P2P_SEND_UNRELIABLE)
packet_index_rot = packet_index_rot + 1
last_rot = get_parent().rotation
func _on_scale_timer_timeout():
if get_parent().scale != last_scale and NetworkManager.GAME_STARTED:
var DATA : Dictionary = {"Idx":packet_index_scale + 1,"player_id":NetworkManager.STEAM_ID,"TYPE":NetworkManager.TYPES.TRANFORM_SYNC,"value":get_parent().scale,"node_path":get_path(),"property":"scale"}
P2P._send_P2P_Packet(0,0, DATA,Steam.P2P_SEND_UNRELIABLE)
packet_index_scale = packet_index_scale + 1
last_scale = get_parent().scale
func _process(delta):
if transform_buffer[0] != null and NetworkManager.GAME_STARTED:
if transform_buffer[0]["Idx"] >= last_index_buffer[0] :
var lerped_value = lerp(get_parent().get(transform_buffer[0]["property"]),transform_buffer[0]["value"],0.1)
get_parent().set(transform_buffer[0]["property"],lerped_value)
last_index_buffer[0] = transform_buffer[0]["Idx"]
# Rotation
if transform_buffer[1] != null and NetworkManager.GAME_STARTED:
if transform_buffer[1]["Idx"] >= last_index_buffer[1]:
var lerped_value = lerp(get_parent().get(transform_buffer[1]["property"]),transform_buffer[1]["value"],0.1)
get_parent().set(transform_buffer[1]["property"],lerped_value)
last_index_buffer[1] = transform_buffer[1]["Idx"]
# Scale
if transform_buffer[2] != null and NetworkManager.GAME_STARTED:
if transform_buffer[2]["Idx"] >= last_index_buffer[2]:
var lerped_value = lerp(get_parent().get(transform_buffer[2]["property"]),transform_buffer[2]["value"],0.1)
get_parent().set(transform_buffer[2]["property"],lerped_value)
last_index_buffer[2] = transform_buffer[2]["Idx"]
func abort():
posTimer.stop()
rotTimer.stop()
sclTimer.stop()
set_process(false)

View File

@ -1,118 +0,0 @@
extends Synchronizer
class_name VoiceSync
var current_sample_rate: int = 48000
var local_playback : AudioStreamGeneratorPlayback = null
var local_voice_buffer: PackedByteArray = PackedByteArray()
var use_optimal_sample_rate: bool = false
var DATA : Dictionary
const REF_SAMPLE_RATE : int = 48000
@export var loopback_enabled : bool = false
@export var audio_node : AudioStreamPlayer
@export var voice_key : String = "push_to_talk"
var streamplay : AudioStreamGenerator
var playback_stream : AudioStreamGeneratorPlayback
func _ready():
change_voice_settings(true)
DATA = {
"steam_id": NetworkManager.STEAM_ID,
"TYPE": NetworkManager.TYPES.VOICE,
"node_path": get_path(),
"voice_data": {}
}
if NetworkManager.LOBBY_MEMBERS.size() > 1:
loopback_enabled = false
if audio_node != null:
audio_node.stream.mix_rate = current_sample_rate
audio_node.play()
local_playback = audio_node.get_stream_playback()
func change_voice_settings(push_to_talk :bool):
if push_to_talk:
Steam.setInGameVoiceSpeaking(NetworkManager.STEAM_ID, false)
Steam.stopVoiceRecording()
set_process_input(true)
else:
Steam.setInGameVoiceSpeaking(NetworkManager.STEAM_ID, true)
Steam.startVoiceRecording()
set_process_input(false)
func record(voice : bool):
Steam.setInGameVoiceSpeaking(NetworkManager.STEAM_ID, voice)
if voice:
Steam.startVoiceRecording()
else:
Steam.stopVoiceRecording()
func check_for_voice() -> void:
var available_voice: Dictionary = Steam.getAvailableVoice()
if available_voice['result'] == Steam.VOICE_RESULT_OK and available_voice['buffer'] > 0:
var voice_data: Dictionary = Steam.getVoice()
if voice_data['result'] == Steam.VOICE_RESULT_OK:
DATA["voice_data"] = voice_data
P2P._send_P2P_Packet(0,0, DATA,Steam.P2P_SEND_RELIABLE)
if loopback_enabled:
process_voice_data(voice_data)
func _process(_delta: float) -> void:
if get_parent().name == str(NetworkManager.STEAM_ID):
check_for_voice()
if Input.is_action_pressed(voice_key):
record(true)
if Input.is_action_just_released(voice_key):
record(false)
func get_sample_rate() -> void:
var optimal_sample_rate: int = Steam.getVoiceOptimalSampleRate()
# SpaceWar uses 11000 for sample rate?!
# If are using Steam's "optimal" rate, set it; otherwise we default to 48000
if use_optimal_sample_rate:
current_sample_rate = optimal_sample_rate
else:
current_sample_rate = 48000
func process_voice_data(voice_data: Dictionary) -> void:
get_sample_rate()
var pitch : float = float(current_sample_rate)/REF_SAMPLE_RATE
audio_node.set_pitch_scale(pitch)
var decompressed_voice: Dictionary = Steam.decompressVoice(
voice_data['buffer'],
current_sample_rate)
if (
not decompressed_voice['result'] == Steam.VOICE_RESULT_OK
):
return
if local_playback != null:
if local_playback.get_frames_available() <= 0:
return
local_voice_buffer = decompressed_voice['uncompressed']
for i: int in range(0, mini(local_playback.get_frames_available() * 2, local_voice_buffer.size()), 2):
var raw_value = local_voice_buffer.decode_s16(i)
# Convert the 16-bit integer to a float on from -1 to 1
var amplitude: float = float(raw_value) / 32768.0
local_playback.push_frame(Vector2(amplitude, amplitude))
#local_voice_buffer.remove_at(0)
#local_voice_buffer.remove_at(0)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

View File

@ -1,34 +0,0 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://d0hi31a5q15pi"
path="res://.godot/imported/funcSyncIcon.png-ee0ebc7f5fc0f5cd37293630b8d418fc.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://addons/godot_steam_sync/Network/RadomeSteamSync/SyncNode/funcSyncIcon.png"
dest_files=["res://.godot/imported/funcSyncIcon.png-ee0ebc7f5fc0f5cd37293630b8d418fc.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

View File

@ -1,34 +0,0 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://dvqalcb5gle3l"
path="res://.godot/imported/propertySyncIcon.png-7230c83490a15b0c58480c84d77bc8ba.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://addons/godot_steam_sync/Network/RadomeSteamSync/SyncNode/propertySyncIcon.png"
dest_files=["res://.godot/imported/propertySyncIcon.png-7230c83490a15b0c58480c84d77bc8ba.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

View File

@ -1,34 +0,0 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://choidi1eihrtd"
path="res://.godot/imported/transformSyncIcon.png-70197aa309a4df07b6cd61ec5f7effd6.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://addons/godot_steam_sync/Network/RadomeSteamSync/SyncNode/transformSyncIcon.png"
dest_files=["res://.godot/imported/transformSyncIcon.png-70197aa309a4df07b6cd61ec5f7effd6.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

View File

@ -1,20 +0,0 @@
@tool
extends EditorPlugin
func _enter_tree() -> void:
add_autoload_singleton("NetworkManager","res://addons/godot_steam_sync/Network/RadomeSteamSync/NetworkManager.gd")
add_autoload_singleton("P2P","res://addons/godot_steam_sync/Network/RadomeSteamSync/P2P.gd")
# add_autoload_singleton("Command","res://addons/godot_steam_sync/Network/RadomeSteamSync/SyncNode/CommandSync.gd")
#add_autoload_singleton("SceneManager","res://addons/godot_steam_sync/SceneChanger/SceneManager.gd")
func _exit_tree() -> void:
remove_autoload_singleton("NetworkManager")
remove_autoload_singleton("P2P")
# remove_autoload_singleton("Command")
#remove_autoload_singleton("SceneManager")

View File

@ -1,7 +0,0 @@
[plugin]
name="GodotSteamSync"
description="Advanced GodotSteam Synchornizer and Lobby System."
author="Radome"
version="0.1"
script="godot_steam_sync.gd"

View File

@ -2,7 +2,7 @@ class_name Interactable
extends Node3D extends Node3D
#var player_reference: Player var player_reference: Player
func interact(): func interact():

View File

@ -0,0 +1,36 @@
[gd_scene load_steps=7 format=3 uid="uid://dm31ddavxv5gt"]
[ext_resource type="Script" path="res://assets/core/interactables/ship-helm/ship_helm.gd" id="1_lsarv"]
[ext_resource type="PackedScene" uid="uid://d2e3plio1db16" path="res://assets/core/interactables/ship-helm/ship_helm.blend" id="2_n3ctg"]
[ext_resource type="Texture2D" uid="uid://becx0d2aass76" path="res://addons/kennysprototypetextures/Purple/texture_purple (1).png" id="3_sgyh6"]
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_vj8ph"]
albedo_texture = ExtResource("3_sgyh6")
uv1_triplanar = true
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_mtdgj"]
albedo_texture = ExtResource("3_sgyh6")
uv1_triplanar = true
[sub_resource type="BoxShape3D" id="BoxShape3D_u6a0w"]
size = Vector3(1, 1.23828, 0.332275)
[node name="ShipHelm" type="StaticBody3D"]
collision_layer = 256
collision_mask = 7
script = ExtResource("1_lsarv")
[node name="ship_helm" parent="." instance=ExtResource("2_n3ctg")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.681346, 0)
[node name="Cube" parent="ship_helm" index="0"]
material_override = SubResource("StandardMaterial3D_vj8ph")
[node name="Torus" parent="ship_helm" index="1"]
material_override = SubResource("StandardMaterial3D_mtdgj")
[node name="CollisionShape3D" type="CollisionShape3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.901878, 0.0608378)
shape = SubResource("BoxShape3D_u6a0w")
[editable path="ship_helm"]

Binary file not shown.

View File

@ -0,0 +1,51 @@
[remap]
importer="scene"
importer_version=1
type="PackedScene"
uid="uid://d2e3plio1db16"
path="res://.godot/imported/ship_helm.blend-ff92b4e852f739448ae2d5004545d8b0.scn"
[deps]
source_file="res://assets/core/interactables/ship-helm/ship_helm.blend"
dest_files=["res://.godot/imported/ship_helm.blend-ff92b4e852f739448ae2d5004545d8b0.scn"]
[params]
nodes/root_type=""
nodes/root_name=""
nodes/apply_root_scale=true
nodes/root_scale=1.0
nodes/import_as_skeleton_bones=false
meshes/ensure_tangents=true
meshes/generate_lods=true
meshes/create_shadow_meshes=true
meshes/light_baking=1
meshes/lightmap_texel_size=0.2
meshes/force_disable_compression=false
skins/use_named_skins=true
animation/import=true
animation/fps=30
animation/trimming=false
animation/remove_immutable_tracks=true
animation/import_rest_as_RESET=false
import_script/path=""
_subresources={}
blender/nodes/visible=0
blender/nodes/active_collection_only=false
blender/nodes/punctual_lights=true
blender/nodes/cameras=true
blender/nodes/custom_properties=true
blender/nodes/modifiers=1
blender/meshes/colors=false
blender/meshes/uvs=true
blender/meshes/normals=true
blender/meshes/tangents=true
blender/meshes/skins=2
blender/meshes/export_bones_deforming_mesh_only=false
blender/materials/unpack_enabled=true
blender/materials/export_materials=1
blender/animation/limit_playback=true
blender/animation/always_sample=true
blender/animation/group_tracks=true

View File

@ -0,0 +1,15 @@
class_name ShipHelm
extends Interactable
@export var parent_ship: Ship
func interact():
if player_reference.is_network_authority:
if !parent_ship.ship_is_piloted:
player_reference.set_is_piloting(true)
parent_ship.set_piloting_player(player_reference)
elif parent_ship.ship_is_piloted:
player_reference.set_is_piloting(false)
parent_ship.remove_piloting_player()

View File

@ -0,0 +1,70 @@
[gd_scene load_steps=3 format=3 uid="uid://7t1x82gvrw8a"]
[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", "leave_button", "start_button", "show_lobbies_button", "user_list_box", "lobby_list_box")]
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
script = ExtResource("1_o4fbq")
host_button = NodePath("Panel/HBoxContainer/Buttons/Host")
leave_button = NodePath("Panel/HBoxContainer/Buttons/Leave")
start_button = NodePath("Panel/HBoxContainer/Buttons/Start")
show_lobbies_button = NodePath("Panel/HBoxContainer/Buttons/ShowLobbies")
user_list_box = NodePath("Panel/HBoxContainer/PlayerList")
lobby_list_box = NodePath("Panel/HBoxContainer/LobbyList")
user_box_prefab = ExtResource("2_dpthk")
[node name="Panel" type="Panel" parent="."]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
[node name="HBoxContainer" type="HBoxContainer" parent="Panel"]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
[node name="Buttons" type="VBoxContainer" parent="Panel/HBoxContainer"]
custom_minimum_size = Vector2(500, 0)
layout_mode = 2
size_flags_horizontal = 6
size_flags_vertical = 4
[node name="Host" type="Button" parent="Panel/HBoxContainer/Buttons"]
layout_mode = 2
size_flags_vertical = 4
text = "Host Lobby"
[node name="Start" type="Button" parent="Panel/HBoxContainer/Buttons"]
layout_mode = 2
disabled = true
text = "Start"
[node name="ShowLobbies" type="Button" parent="Panel/HBoxContainer/Buttons"]
layout_mode = 2
text = "Show Lobbies"
[node name="Leave" type="Button" parent="Panel/HBoxContainer/Buttons"]
layout_mode = 2
disabled = true
text = "Leave Lobby"
[node name="PlayerList" type="VBoxContainer" parent="Panel/HBoxContainer"]
visible = false
layout_mode = 2
size_flags_horizontal = 3
[node name="LobbyList" type="VBoxContainer" parent="Panel/HBoxContainer"]
visible = false
layout_mode = 2

View File

@ -0,0 +1,20 @@
[gd_scene load_steps=2 format=3 uid="uid://biryul3n6thlw"]
[ext_resource type="Texture2D" uid="uid://fwub8fvl2u4i" path="res://addons/ingameconsole/ps1hagrid.png" id="1_gtutw"]
[node name="UserBox" type="HBoxContainer"]
offset_right = 610.0
offset_bottom = 128.0
[node name="PFP" type="TextureRect" parent="."]
custom_minimum_size = Vector2(128, 128)
layout_mode = 2
size_flags_horizontal = 4
texture = ExtResource("1_gtutw")
expand_mode = 1
[node name="Username" type="Label" parent="."]
layout_mode = 2
size_flags_horizontal = 3
text = "Hagrid 1"
horizontal_alignment = 1

View File

@ -0,0 +1,418 @@
extends Node
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 = []
var lobby_members_max: int = 10
var lobby_vote_kick: bool = false
var lobby_type: int = Steam.LOBBY_TYPE_PUBLIC
var steam_id: int = 0
var steam_username: String = ""
var avatar_texture_cache: Dictionary = {}
var is_host: bool = false
var host_id: int
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 on_lobbies_received(these_lobbies: Array)
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()
func _process(_delta: float) -> void:
Steam.run_callbacks()
if lobby_id > 0:
read_all_p2p_packets()
func _init_steam() -> void:
var init_result = Steam.steamInitEx(true, STEAM_APP_ID)
print("Steam Init Result: " + str(init_result))
if init_result['status'] > 0:
printerr("Steam failed to initialize, shutting down: " + str(init_result))
#get_tree().quit()
steam_id = Steam.getSteamID()
steam_username = Steam.getFriendPersonaName(steam_id)
Steam.p2p_session_request.connect(_on_p2p_session_request)
Steam.p2p_session_connect_fail.connect(_on_p2p_session_connect_fail)
Steam.join_requested.connect(_on_lobby_join_requested)
Steam.lobby_chat_update.connect(_on_lobby_chat_update)
Steam.lobby_created.connect(_on_lobby_created)
#Steam.lobby_data_update.connect(_on_lobby_data_update)
#Steam.lobby_invite.connect(_on_lobby_invite)
Steam.lobby_joined.connect(_on_lobby_joined)
Steam.lobby_match_list.connect(_on_lobby_match_list)
Steam.lobby_message.connect(_on_lobby_message)
Steam.persona_state_change.connect(_on_persona_change)
func _on_lobby_join_requested(this_lobby_id: int, friend_id: int):
var owner_name: String = Steam.getFriendPersonaName(friend_id)
print("Trying to join " + owner_name + "'s lobby...")
join_lobby(this_lobby_id)
func _on_lobby_chat_update(this_lobby_id: int, change_id: int, making_change_id: int, chat_state: int) -> void:
var changer_name: String = Steam.getFriendPersonaName(change_id)
# If a player has joined the lobby
if chat_state == Steam.CHAT_MEMBER_STATE_CHANGE_ENTERED:
print("%s has joined the lobby." % changer_name)
elif chat_state == Steam.CHAT_MEMBER_STATE_CHANGE_LEFT:
user_left_lobby.emit(change_id)
print("%s has left the lobby." % changer_name)
elif chat_state == Steam.CHAT_MEMBER_STATE_CHANGE_KICKED:
print("%s has been kicked from the lobby." % changer_name)
elif chat_state == Steam.CHAT_MEMBER_STATE_CHANGE_BANNED:
print("%s has been banned from the lobby." % changer_name)
else:
print("%s did... something." % changer_name)
get_lobby_members()
func _on_lobby_created(connect: int, this_lobby_id: int) -> void:
if connect == 1:
lobby_id = this_lobby_id
lobby_created.emit(lobby_id)
print("Lobby created with ID: " + str(lobby_id))
Steam.setLobbyJoinable(lobby_id, true)
Steam.setLobbyData(lobby_id, "name", str(steam_username) + "'s Lobby")
var set_relay: bool = Steam.allowP2PPacketRelay(true)
#func _on_lobby_data_update():
# pass
#func _on_lobby_invite():
# pass
func _on_lobby_joined(this_lobby_id: int, _permissions: int, _locked: bool, response: int) -> void:
if response == Steam.CHAT_ROOM_ENTER_RESPONSE_SUCCESS:
lobby_id = this_lobby_id
get_lobby_members()
make_p2p_handshake()
lobby_joined.emit(lobby_id)
else:
var fail_reason: String
match response:
Steam.CHAT_ROOM_ENTER_RESPONSE_DOESNT_EXIST: fail_reason = "This lobby no longer exists."
Steam.CHAT_ROOM_ENTER_RESPONSE_NOT_ALLOWED: fail_reason = "You don't have permission to join this lobby."
Steam.CHAT_ROOM_ENTER_RESPONSE_FULL: fail_reason = "The lobby is now full."
Steam.CHAT_ROOM_ENTER_RESPONSE_ERROR: fail_reason = "Uh... something unexpected happened!"
Steam.CHAT_ROOM_ENTER_RESPONSE_BANNED: fail_reason = "You are banned from this lobby."
Steam.CHAT_ROOM_ENTER_RESPONSE_LIMITED: fail_reason = "You cannot join due to having a limited account."
Steam.CHAT_ROOM_ENTER_RESPONSE_CLAN_DISABLED: fail_reason = "This lobby is locked or disabled."
Steam.CHAT_ROOM_ENTER_RESPONSE_COMMUNITY_BAN: fail_reason = "This lobby is community locked."
Steam.CHAT_ROOM_ENTER_RESPONSE_MEMBER_BLOCKED_YOU: fail_reason = "A user in the lobby has blocked you from joining."
Steam.CHAT_ROOM_ENTER_RESPONSE_YOU_BLOCKED_MEMBER: fail_reason = "A user you have blocked is in the lobby."
print("Failed to join this chat room: %s" % fail_reason)
func _on_lobby_match_list(these_lobbies: Array) -> void:
on_lobbies_received.emit(these_lobbies)
func _on_lobby_message():
pass
func _on_persona_change(this_steam_id: int, _flags: int) -> void:
if lobby_id > 0 and lobby_members:
for member in lobby_members:
if member["steam_id"] == this_steam_id:
var user: String = str(this_steam_id) + ":" + Steam.getFriendPersonaName(this_steam_id)
print("User (%s) had information change, updating lobby list." % user)
get_lobby_members()
break
func _on_p2p_session_request(remote_id: int):
var this_requester: String = Steam.getFriendPersonaName(remote_id)
print("P2P session request from: " + this_requester)
Steam.acceptP2PSessionWithUser(remote_id)
make_p2p_handshake()
func _on_p2p_session_connect_fail(steam_id: int, session_error: int) -> void:
# If no error was given
if session_error == 0:
print("WARNING: Session failure with %s: no error given" % steam_id)
# Else if target user was not running the same game
elif session_error == 1:
print("WARNING: Session failure with %s: target user not running the same game" % steam_id)
# Else if local user doesn't own app / game
elif session_error == 2:
print("WARNING: Session failure with %s: local user doesn't own app / game" % steam_id)
# Else if target user isn't connected to Steam
elif session_error == 3:
print("WARNING: Session failure with %s: target user isn't connected to Steam" % steam_id)
# Else if connection timed out
elif session_error == 4:
print("WARNING: Session failure with %s: connection timed out" % steam_id)
# Else if unused
elif session_error == 5:
print("WARNING: Session failure with %s: unused" % steam_id)
# Else no known error
else:
print("WARNING: Session failure with %s: unknown error %s" % [steam_id, session_error])
func host_lobby():
if lobby_id == 0:
Steam.createLobby(lobby_type, lobby_members_max)
is_host = true
host_id = steam_id
else:
printerr("Cannot host lobby, already in a lobby")
func join_lobby(this_lobby_id: int):
print("Attempting to join lobby: " + str(this_lobby_id))
lobby_members.clear()
Steam.joinLobby(this_lobby_id)
host_id = Steam.getLobbyOwner(this_lobby_id)
func leave_lobby():
if lobby_id != 0:
Steam.leaveLobby(lobby_id)
lobby_id = 0
host_id = 0
for this_member in lobby_members:
if this_member["steam_id"] != steam_id:
Steam.closeP2PSessionWithUser(this_member["steam_id"])
lobby_members.clear()
print("Left lobby.")
func get_lobbies():
Steam.addRequestLobbyListDistanceFilter(Steam.LOBBY_DISTANCE_FILTER_WORLDWIDE)
Steam.requestLobbyList()
func get_lobby_members():
lobby_members.clear()
var member_count: int = Steam.getNumLobbyMembers(lobby_id)
for this_member in range(0, member_count):
var member_steam_id: int = Steam.getLobbyMemberByIndex(lobby_id, this_member)
var member_steam_name: String = Steam.getFriendPersonaName(member_steam_id)
lobby_members.append({"steam_id":member_steam_id, "steam_name":member_steam_name})
user_joined_lobby.emit(member_steam_id)
await request_player_avatar(member_steam_id)
func make_p2p_handshake():
print("Sending p2p handshake to the lobby...")
send_p2p_packet(0, {"message":"handshake", "from":steam_id})
func send_p2p_packet(target: int, packet_data: Dictionary) -> void:
# Set the send_type and channel
var send_type: int = Steam.P2P_SEND_RELIABLE
var channel: int = 0
# Create a data array to send the data through
var this_data: PackedByteArray
# Compress the PackedByteArray we create from our dictionary using the GZIP compression method
var compressed_data: PackedByteArray = var_to_bytes(packet_data).compress(FileAccess.COMPRESSION_GZIP)
this_data.append_array(compressed_data)
# If sending a packet to everyone
if target == 0:
# If there is more than one user, send packets
if lobby_members.size() > 1:
# Loop through all members that aren't you
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'])
# If sending a packet to everyone except the host
elif target == 1:
if lobby_members.size() > 1:
# Loop through all members that aren't the host
for this_member in lobby_members:
if this_member['steam_id'] != host_id:
Steam.sendP2PPacket(this_member['steam_id'], this_data, send_type, channel)
# Else send it to someone specific
else:
Steam.sendP2PPacket(target, this_data, send_type, channel)
func read_all_p2p_packets(read_count: int = 0):
if read_count >= PACKET_READ_LIMIT:
return
if Steam.getAvailableP2PPacketSize(0) > 0:
read_p2p_packet()
read_all_p2p_packets(read_count + 1)
func read_p2p_packet() -> void:
var packet_size: int = Steam.getAvailableP2PPacketSize(0)
# There is a packet
if packet_size > 0:
var this_packet: Dictionary = Steam.readP2PPacket(packet_size, 0)
if this_packet.is_empty() or this_packet == null:
print("WARNING: read an empty packet with non-zero size!")
# Get the remote user's ID
var packet_sender: int = this_packet['remote_steam_id']
# Make the packet data readable
var packet_code: PackedByteArray = this_packet['data']
# 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))
# 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"])
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:
var avatar_texture: ImageTexture = null
Steam.getPlayerAvatar(Steam.AVATAR_LARGE, user_id)
print("Attempting to get avatar for " + Steam.getFriendPersonaName(user_id) + ".....")
Steam.avatar_loaded.connect(func(loaded_user_id: int, avatar_size: int, avatar_buffer: PackedByteArray):
if loaded_user_id == user_id:
var avatar_image: Image = Image.create_from_data(avatar_size, avatar_size, false, Image.FORMAT_RGBA8, avatar_buffer)
if avatar_size != size:
avatar_image.resize(size, size, Image.INTERPOLATE_LANCZOS)
avatar_texture = ImageTexture.create_from_image(avatar_image)
avatar_texture_cache[user_id] = avatar_texture
)
while not avatar_texture_cache.has(user_id):
await get_tree().process_frame
func get_player_avatar(user_id: int) -> ImageTexture:
if avatar_texture_cache.has(user_id):
return avatar_texture_cache[user_id]
else:
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"])
player.steam_id = 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_to_host(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(host_id, packet_data)
func sync_property_to_peer(node_id: String, property_name: String, value: Variant, target_peer: int):
var packet_data = {"message":"property_update", "node_id": node_id, "property_name": property_name, "value": value}
send_p2p_packet(target_peer, packet_data)
func sync_property_to_all(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)
func sync_property_to_all_except_host(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(1, packet_data)

View File

@ -1,7 +0,0 @@
extends Node
func change_scene(path: String):
var packet: Dictionary = {'TYPE': NetworkManager.TYPES.CHANGE_SCENE,'scene': path}
P2P._send_P2P_Packet(0, 0, packet, Steam.P2P_SEND_RELIABLE)
get_tree().change_scene_to_file(path)

View File

@ -0,0 +1,193 @@
extends Control
@export var host_button: Button
@export var leave_button: Button
@export var start_button: Button
@export var show_lobbies_button: Button
@export var user_list_box: VBoxContainer
@export var lobby_list_box: VBoxContainer
@export var user_box_prefab: PackedScene
var added_users = []
func _ready() -> void:
host_button.pressed.connect(_on_host)
leave_button.pressed.connect(_on_leave)
start_button.pressed.connect(_on_start)
show_lobbies_button.pressed.connect(_on_show_lobbies)
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)
NetworkManager.on_lobbies_received.connect(_on_lobbies_received)
GameConsole.register_command(Command.new("update", update_ui, [], "Updates the lobby UI"))
func _on_host():
NetworkManager.host_lobby()
show_lobbies_button.disabled = true
func _on_leave():
NetworkManager.leave_lobby()
reset_ui()
func _on_show_lobbies():
lobby_list_box.visible = true
NetworkManager.get_lobbies()
func _on_lobbies_received(these_lobbies: Array):
var friend_lobbies = get_lobbies_with_friends()
# Clear the lobby list box before adding new lobbies
for child in lobby_list_box.get_children():
child.queue_free()
if friend_lobbies.size() == 0:
var no_lobbies_label = Label.new()
no_lobbies_label.text = "No lobbies available"
lobby_list_box.add_child(no_lobbies_label)
else:
for lobby_id in friend_lobbies.keys():
# Pull lobby data from Steam, these are specific to our example
var lobby_name: String = Steam.getLobbyData(lobby_id, "name")
var lobby_mode: String = Steam.getLobbyData(lobby_id, "mode")
# Get the current number of members
var lobby_num_members: int = Steam.getNumLobbyMembers(lobby_id)
# Create a button for the lobby
var lobby_button: Button = Button.new()
lobby_button.set_text(lobby_name + " " + str(lobby_num_members) + "/" + str(Steam.getLobbyMemberLimit(lobby_id)))
lobby_button.set_size(Vector2(800, 50))
lobby_button.set_name("lobby_%s" % lobby_id)
lobby_button.connect("pressed", Callable(self, "join_lobby").bind(lobby_id))
# Add the new lobby to the list
lobby_list_box.add_child(lobby_button)
func get_lobbies_with_friends() -> Dictionary:
var results: Dictionary = {}
for i in range(0, Steam.getFriendCount()):
var steam_id: int = Steam.getFriendByIndex(i, Steam.FRIEND_FLAG_IMMEDIATE)
var game_info: Dictionary = Steam.getFriendGamePlayed(steam_id)
if game_info.is_empty():
# This friend is not playing a game
continue
else:
# They are playing a game, check if it's the same game as ours
var app_id: int = game_info['id']
var lobby = game_info['lobby']
if app_id != Steam.getAppID() or lobby is String:
# Either not in this game, or not in a lobby
continue
if not results.has(lobby):
results[lobby] = []
results[lobby].append(steam_id)
return results
func get_friends_in_lobbies() -> Dictionary:
var results: Dictionary = {}
for i in range(0, Steam.getFriendCount()):
var steam_id: int = Steam.getFriendByIndex(i, Steam.FRIEND_FLAG_IMMEDIATE)
var game_info: Dictionary = Steam.getFriendGamePlayed(steam_id)
if game_info.is_empty():
# This friend is not playing a game
continue
else:
# They are playing a game, check if it's the same game as ours
var app_id: int = game_info['id']
var lobby = game_info['lobby']
if app_id != Steam.getAppID() or lobby is String:
# Either not in this game, or not in a lobby
continue
results[steam_id] = lobby
return results
func join_lobby(lobby_id: int):
NetworkManager.join_lobby(lobby_id)
func _on_lobby_created(lobby_id: int):
print("Lobby created")
host_button.disabled = true
leave_button.disabled = false
start_button.disabled = false
user_list_box.visible = true
func _on_lobby_joined(lobby_id: int):
host_button.disabled = true
leave_button.disabled = false
user_list_box.visible = true
lobby_list_box.visible = false
func _on_user_joined_lobby(user_id: int):
if user_id in added_users:
return # User already added, skip
added_users.append(user_id)
update_ui()
func _on_user_left_lobby(user_id: int):
added_users.erase(user_id)
update_ui()
func _on_start():
NetworkManager.start_game()
visible = false
func _on_game_started():
visible = false
func reset_ui():
host_button.disabled = false
leave_button.disabled = true
start_button.disabled = true
user_list_box.visible = false
lobby_list_box.visible = false
show_lobbies_button.disabled = false
added_users.clear()
for child in user_list_box.get_children():
child.queue_free()
for child in lobby_list_box.get_children():
child.queue_free()
func update_ui() -> void:
for child in user_list_box.get_children():
child.queue_free()
for user_id in added_users:
var user_box = user_box_prefab.instantiate()
user_box.get_node("Username").text = str(Steam.getFriendPersonaName(user_id))
user_list_box.add_child(user_box)
var avatar_texture = await NetworkManager.get_player_avatar(user_id)
user_box.get_node("PFP").texture = avatar_texture

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

View File

@ -2,16 +2,16 @@
importer="texture" importer="texture"
type="CompressedTexture2D" type="CompressedTexture2D"
uid="uid://14sorpwfe4hf" uid="uid://c3lblkyavjtol"
path="res://.godot/imported/1.png-d99a973fff7536c0ce6f3facaed6e0f4.ctex" path="res://.godot/imported/2d_crosshair_dot.png-61f11b68155f3e5bb55efff33412dc26.ctex"
metadata={ metadata={
"vram_texture": false "vram_texture": false
} }
[deps] [deps]
source_file="res://addons/godot_steam_sync/Media/1.png" source_file="res://assets/core/player-controller/2d_crosshair_dot.png"
dest_files=["res://.godot/imported/1.png-d99a973fff7536c0ce6f3facaed6e0f4.ctex"] dest_files=["res://.godot/imported/2d_crosshair_dot.png-61f11b68155f3e5bb55efff33412dc26.ctex"]
[params] [params]

View File

@ -0,0 +1,8 @@
shader_type canvas_item;
uniform sampler2D SCREEN_TEXTURE : hint_screen_texture, filter_linear_mipmap;
void fragment(){
vec4 color = vec4(texture(SCREEN_TEXTURE, SCREEN_UV).rgb, texture(TEXTURE, UV).a);
COLOR = vec4(1.0 - color.rgb, color.a);
}

View File

@ -0,0 +1,35 @@
[gd_scene load_steps=5 format=3 uid="uid://c6w0ivy4hetrl"]
[ext_resource type="Script" path="res://assets/core/player-controller/scripts/player.gd" id="1_bv7t4"]
[ext_resource type="Script" path="res://assets/core/player-controller/scripts/player_interacter.gd" id="2_wvu3d"]
[sub_resource type="CapsuleMesh" id="CapsuleMesh_v7b3h"]
radius = 0.35
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_qlkab"]
radius = 0.35
[node name="Player" type="CharacterBody3D" node_paths=PackedStringArray("camera")]
script = ExtResource("1_bv7t4")
camera = NodePath("Neck/Camera3D")
[node name="PlayerTag" type="Label3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.26654, 0)
billboard = 1
text = "username"
[node name="MeshInstance3D" type="MeshInstance3D" parent="."]
mesh = SubResource("CapsuleMesh_v7b3h")
[node name="CollisionShape3D" type="CollisionShape3D" parent="."]
shape = SubResource("CapsuleShape3D_qlkab")
[node name="Neck" type="Node3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.65, 0)
[node name="Camera3D" type="Camera3D" parent="Neck"]
[node name="RayCast3D" type="RayCast3D" parent="Neck/Camera3D" node_paths=PackedStringArray("player")]
target_position = Vector3(0, 0, -2.5)
script = ExtResource("2_wvu3d")
player = NodePath("../../..")

View File

@ -0,0 +1,130 @@
[gd_scene load_steps=12 format=3 uid="uid://c6w0ivy4hetrl"]
[ext_resource type="Script" path="res://assets/core/player-controller/scripts/player.gd" id="1_bv7t4"]
[ext_resource type="Texture2D" uid="uid://fwub8fvl2u4i" path="res://addons/ingameconsole/ps1hagrid.png" id="2_omgn1"]
[ext_resource type="Script" path="res://assets/core/player-controller/scripts/player_interacter.gd" id="2_wvu3d"]
[ext_resource type="Script" path="res://assets/core/player-controller/scripts/player_hud.gd" id="3_02ne1"]
[ext_resource type="Shader" path="res://assets/core/player-controller/scenes/inverted_crosshair.gdshader" id="3_rakxt"]
[ext_resource type="Texture2D" uid="uid://c3lblkyavjtol" path="res://assets/core/player-controller/2d_crosshair_dot.png" id="4_3uwxe"]
[sub_resource type="CapsuleMesh" id="CapsuleMesh_v7b3h"]
radius = 0.35
height = 1.5
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_qlkab"]
radius = 0.35
[sub_resource type="SphereMesh" id="SphereMesh_vu2l8"]
radius = 0.35
height = 0.7
[sub_resource type="ShaderMaterial" id="ShaderMaterial_wmxrr"]
shader = ExtResource("3_rakxt")
[sub_resource type="ShaderMaterial" id="ShaderMaterial_0n7pd"]
shader = ExtResource("3_rakxt")
[node name="Player" type="CharacterBody3D" node_paths=PackedStringArray("camera", "neck", "player_avatar_face", "body", "head", "player_hud")]
collision_mask = 242
script = ExtResource("1_bv7t4")
camera = NodePath("Neck/Camera3D")
neck = NodePath("Neck")
player_avatar_face = NodePath("Neck/Camera3D/PlayerAvatarFace")
body = NodePath("Body")
head = NodePath("Neck/Head")
player_hud = NodePath("PlayerHUD")
[node name="PlayerTag" type="Label3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.26654, 0)
visibility_range_begin = 0.7
visibility_range_end = 15.0
billboard = 1
text = "username"
[node name="Body" type="MeshInstance3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.5, 0)
mesh = SubResource("CapsuleMesh_v7b3h")
[node name="CollisionShape3D" type="CollisionShape3D" parent="."]
shape = SubResource("CapsuleShape3D_qlkab")
[node name="Neck" type="Node3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.65, 0)
[node name="Camera3D" type="Camera3D" parent="Neck"]
[node name="RayCast3D" type="RayCast3D" parent="Neck/Camera3D" node_paths=PackedStringArray("player")]
target_position = Vector3(0, 0, -2.5)
collision_mask = 256
script = ExtResource("2_wvu3d")
player = NodePath("../../..")
[node name="PlayerAvatarFace" type="Sprite3D" parent="Neck/Camera3D"]
transform = Transform3D(-0.1, 0, -8.74228e-09, 0, 0.1, 0, 8.74228e-09, 0, -0.1, 0, 0, -0.349588)
flip_h = true
shaded = true
double_sided = false
texture = ExtResource("2_omgn1")
[node name="Head" type="MeshInstance3D" parent="Neck"]
mesh = SubResource("SphereMesh_vu2l8")
[node name="PlayerHUD" type="CanvasLayer" parent="." node_paths=PackedStringArray("fps_label")]
script = ExtResource("3_02ne1")
fps_label = NodePath("Debug/HBoxContainer/VBoxContainer/MarginContainer/FPSLabel")
[node name="Overlay" type="Control" parent="PlayerHUD"]
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
mouse_filter = 1
[node name="CenterContainer" type="CenterContainer" parent="PlayerHUD/Overlay"]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
[node name="TextureRect" type="TextureRect" parent="PlayerHUD/Overlay/CenterContainer"]
material = SubResource("ShaderMaterial_wmxrr")
layout_mode = 2
texture = ExtResource("4_3uwxe")
[node name="Debug" type="Control" parent="PlayerHUD"]
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
mouse_filter = 1
[node name="HBoxContainer" type="HBoxContainer" parent="PlayerHUD/Debug"]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
alignment = 2
[node name="VBoxContainer" type="VBoxContainer" parent="PlayerHUD/Debug/HBoxContainer"]
layout_mode = 2
[node name="MarginContainer" type="MarginContainer" parent="PlayerHUD/Debug/HBoxContainer/VBoxContainer"]
layout_mode = 2
theme_override_constants/margin_top = 5
theme_override_constants/margin_right = 5
[node name="FPSLabel" type="Label" parent="PlayerHUD/Debug/HBoxContainer/VBoxContainer/MarginContainer"]
material = SubResource("ShaderMaterial_0n7pd")
layout_mode = 2
theme_override_font_sizes/font_size = 35
text = "999 FPS"
horizontal_alignment = 2
vertical_alignment = 1

View File

@ -0,0 +1,202 @@
class_name Player extends CharacterBody3D
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.0
@export_range(10, 400, 1) var acceleration: float = 100.0
@export_range(0.1, 3.0, 0.1) var jump_height: float = 1.0
@export_range(0.1, 3.0, 0.1, "or_greater") var camera_sens: float = 1.0
@export_range(0.1, 3.0, 0.1, "or_greater") var joystick_camera_sens_multiplier: float = 5.0
@export var camera: Camera3D
@export var neck: Node3D
@export var player_avatar_face: Sprite3D
@export var body: MeshInstance3D
@export var head: MeshInstance3D
@export var player_hud: CanvasLayer
var jumping: bool = false
var is_using_joystick: bool = false
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 jump_vel: Vector3 # Jumping velocity
var current_ship: Ship
var previous_global_position: Vector3
var previous_global_rotation: Vector3
var previous_head_vert_rotation: Vector3
var neck_rotation_sync: Vector3
func _ready() -> void:
NetworkManager.property_update_received.connect(_on_property_update)
network_uuid = NetworkManager.register_node(self)
player_tag = get_node("PlayerTag")
player_tag.text = username
player_avatar_face.texture = await NetworkManager.get_player_avatar(steam_id)
if is_network_authority:
camera.make_current()
body.hide()
head.hide()
player_avatar_face.hide()
Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
else:
player_hud.hide()
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()
if Input.mouse_mode == Input.MOUSE_MODE_CAPTURED:
if event is InputEventMouseMotion:
is_using_joystick = false
look_dir = event.relative * 0.001
_rotate_camera()
elif event is InputEventJoypadMotion:
is_using_joystick = true
if Input.is_action_just_pressed("jump") and !is_piloting:
jumping = true
func _physics_process(delta: float) -> void:
if !is_network_authority: return
if is_piloting and current_ship != null:
velocity = Vector3.ZERO + _gravity(delta)
else:
velocity = walk(delta) + _gravity(delta) + _jump(delta)
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_to_all(network_uuid, "global_position", global_position)
previous_global_position = global_position
if previous_global_rotation != global_rotation:
NetworkManager.sync_property_to_all(network_uuid, "global_rotation", global_rotation)
previous_global_rotation = global_rotation
if previous_head_vert_rotation != neck.rotation:
NetworkManager.sync_property_to_all(network_uuid, "neck_rotation_sync", neck_rotation_sync)
previous_global_rotation = neck.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
rotation.y -= look_dir.x * camera_sens_final * sens_mod
neck.rotation.x = clamp(neck.rotation.x - look_dir.y * camera_sens_final * sens_mod, -1.5, 1.5)
neck_rotation_sync = neck.rotation
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:
look_dir += joypad_dir * delta
_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")
var _forward: Vector3 = neck.global_transform.basis * Vector3(move_dir.x, 0, move_dir.y)
var walk_dir: Vector3 = Vector3(_forward.x, 0, _forward.z).normalized()
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)
jumping = false
return jump_vel
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))
func ship_entered(_ship: Ship):
current_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):
if property_name == "neck_rotation_sync" and !is_network_authority:
neck.rotation = value
else:
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))

View File

@ -0,0 +1,7 @@
extends CanvasLayer
@export var fps_label: Label
func _process(delta):
fps_label.text = str(Engine.get_frames_per_second()) + " FPS"

View File

@ -0,0 +1,16 @@
extends RayCast3D
@export var player: Player
var current_interactable: Interactable
var has_processed_interact_frame: bool = false
func _process(delta):
if is_colliding() and get_collider() is Interactable:
if Input.is_action_just_pressed("interact") and !has_processed_interact_frame:
current_interactable = get_collider() as Interactable
GameConsole.log_debug("interacted with interactable: " + current_interactable.name)
current_interactable.player_reference = player
current_interactable.interact()
has_processed_interact_frame = true
has_processed_interact_frame = false

View File

@ -0,0 +1,168 @@
class_name Ship
extends RigidBody3D
@export var player_detection_area: Area3D
@export var helm_location_marker: Marker3D
@export var base_turn_speed: float = 50.0
@export var max_turn_speed: float = 50.0
@export var base_lift_speed: float = 50.0
@export var top_speed: float = 50.0
@export var move_speed: float = 50.0
@export var acceleration: float = 5.0 # Increased acceleration for smoother interpolation
@export var interpolation_damp: float = 0.1 # Damping for smoother rotation
var piloting_player: Player = null
var ship_is_piloted: bool = false
var target_position: Vector3 = Vector3.ZERO
var target_rotation: Quaternion = Quaternion()
var predicted_position: Vector3
var predicted_rotation: Quaternion
var last_input_time: float = 0.0
var network_uuid: String = ""
func _ready():
network_uuid = NetworkManager.register_node(self)
NetworkManager.property_update_received.connect(_on_property_update)
# Preserve current position and rotation at the start
target_position = global_position
target_rotation = global_transform.basis.get_rotation_quaternion()
predicted_position = global_position
predicted_rotation = global_transform.basis.get_rotation_quaternion()
player_detection_area.body_entered.connect(_on_player_entered)
player_detection_area.body_exited.connect(_on_player_exited)
func _process(delta: float):
if ship_is_piloted:
if piloting_player.steam_id == NetworkManager.steam_id:
# This player is piloting
handle_input(delta)
send_network_update()
else:
# Another player is piloting, interpolate
interpolate_position_and_rotation(delta)
else:
# No one is piloting, just interpolate
interpolate_position_and_rotation(delta)
func handle_input(delta: float):
var forward_input = 0.0
var turn_input = 0.0
var vertical_input = 0.0
# Forward and backward movement
if Input.is_action_pressed("move_forwards"):
forward_input += 1
if Input.is_action_pressed("move_backwards"):
forward_input -= 1
# Left and right turning
if Input.is_action_pressed("move_left"):
turn_input += 1
if Input.is_action_pressed("move_right"):
turn_input -= 1
# Up and down movement
if Input.is_action_pressed("jump"):
vertical_input += 1
if Input.is_action_pressed("crouch"):
vertical_input -= 1
# Apply torque for turning
if turn_input != 0:
var torque = Vector3.UP * turn_input * base_turn_speed
apply_torque(torque)
# Clamp the angular velocity to the maximum turn speed
if angular_velocity.length() > max_turn_speed:
angular_velocity = angular_velocity.normalized() * max_turn_speed
# Apply force for forward and backward movement
if forward_input != 0:
var forward_direction = -global_transform.basis.z.normalized()
var forward_force = forward_direction * forward_input * move_speed
apply_central_force(forward_force)
# Apply force for vertical movement
if vertical_input != 0:
var vertical_force = Vector3.UP * vertical_input * base_lift_speed
apply_central_force(vertical_force)
# Update predicted state
predicted_position = predict_position(delta)
predicted_rotation = predict_rotation(delta)
last_input_time = Time.get_ticks_msec()
func predict_position(delta: float):
var velocity = linear_velocity
return global_position + velocity * delta
func predict_rotation(delta: float):
var angular_velocity_quat = Quaternion(Vector3.UP, angular_velocity.y * delta)
return global_transform.basis.get_rotation_quaternion() * angular_velocity_quat
func interpolate_position_and_rotation(delta: float):
# Smooth interpolation with damping
global_position = lerp(global_position, target_position, 1.0 - exp(-acceleration * delta))
global_transform.basis = Basis(slerp_damp(global_transform.basis.get_rotation_quaternion(), target_rotation, interpolation_damp, 1.0))
func slerp_damp(from: Quaternion, to: Quaternion, damping: float, dt: float):
var t = 1.0 - exp(-damping * dt)
return from.slerp(to, t)
func send_network_update():
if NetworkManager.is_host and ship_is_piloted and piloting_player.steam_id == NetworkManager.steam_id:
# Host is piloting, synchronize with clients
NetworkManager.sync_property_to_all_except_host(network_uuid, "global_position", predicted_position)
NetworkManager.sync_property_to_all_except_host(network_uuid, "global_rotation", predicted_rotation)
elif !NetworkManager.is_host and ship_is_piloted and piloting_player.steam_id == NetworkManager.steam_id:
# Client is piloting, send updates to the host
NetworkManager.sync_property_to_all_except_host(network_uuid, "global_position", predicted_position)
NetworkManager.sync_property_to_all_except_host(network_uuid, "global_rotation", predicted_rotation)
func receive_global_position_update(value: Vector3):
target_position = value
func receive_global_rotation_update(value: Quaternion):
target_rotation = value
func _on_player_entered(body):
if body is Player and body.get_parent() != self:
if !body.is_network_authority: return
body.call_deferred("reparent", self, true)
body.ship_entered(self)
print("Player entered the ship area.")
func _on_player_exited(body):
if body is Player and body.get_parent() != get_node("/root/DevLevel/"):
if !body.is_network_authority: return
body.call_deferred("reparent", get_node("/root/DevLevel/"), true)
body.ship_exited()
print("Player exited the ship area.")
func set_piloting_player(player: Player):
piloting_player = player
ship_is_piloted = piloting_player != null
if piloting_player:
print("Player", piloting_player.username, "is now piloting the ship.")
else:
print("The ship is no longer piloted.")
func remove_piloting_player():
piloting_player = null
ship_is_piloted = false
print("The ship is no longer piloted.")
func _on_property_update(node_id: String, property_name: String, value: Variant) -> void:
if NetworkManager.node_map.has(node_id) and node_id == network_uuid:
if property_name == "global_position":
receive_global_position_update(value)
elif property_name == "global_rotation":
receive_global_rotation_update(value)
else:
var node = NetworkManager.node_map[node_id]
node.set(property_name, value)

View File

@ -1,6 +1,8 @@
[gd_scene load_steps=6 format=3 uid="uid://y0xb2vktsr1k"] [gd_scene load_steps=8 format=3 uid="uid://y0xb2vktsr1k"]
[ext_resource type="Script" path="res://assets/core/ships/ship_script.gd" id="1_ghft7"]
[ext_resource type="Texture2D" uid="uid://gymb0tju4y67" path="res://addons/kennysprototypetextures/Dark/texture_black (1).png" id="2_3koq8"] [ext_resource type="Texture2D" uid="uid://gymb0tju4y67" path="res://addons/kennysprototypetextures/Dark/texture_black (1).png" id="2_3koq8"]
[ext_resource type="PackedScene" uid="uid://dm31ddavxv5gt" path="res://assets/core/interactables/ship-helm/ship-helm.tscn" id="3_eyiku"]
[sub_resource type="BoxShape3D" id="BoxShape3D_6gbwt"] [sub_resource type="BoxShape3D" id="BoxShape3D_6gbwt"]
size = Vector3(5, 0.15, 20) size = Vector3(5, 0.15, 20)
@ -15,11 +17,15 @@ size = Vector3(5, 0.15, 20)
[sub_resource type="BoxShape3D" id="BoxShape3D_7o08p"] [sub_resource type="BoxShape3D" id="BoxShape3D_7o08p"]
size = Vector3(4.99609, 3.11252, 20.0022) size = Vector3(4.99609, 3.11252, 20.0022)
[node name="ShuttleClass" type="RigidBody3D"] [node name="ShuttleClass" type="RigidBody3D" node_paths=PackedStringArray("player_detection_area", "helm_location_marker")]
collision_layer = 8 collision_layer = 8
collision_mask = 200 collision_mask = 200
mass = 700.0 mass = 700.0
gravity_scale = 0.0 gravity_scale = 0.0
script = ExtResource("1_ghft7")
player_detection_area = NodePath("PlayerDetectionArea")
helm_location_marker = NodePath("HelmLocationMarker")
base_lift_speed = 5.0
[node name="ShipToShipCol" type="CollisionShape3D" parent="."] [node name="ShipToShipCol" type="CollisionShape3D" parent="."]
shape = SubResource("BoxShape3D_6gbwt") shape = SubResource("BoxShape3D_6gbwt")
@ -44,3 +50,7 @@ shape = SubResource("BoxShape3D_7o08p")
[node name="HelmLocationMarker" type="Marker3D" parent="."] [node name="HelmLocationMarker" type="Marker3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.1, 0) transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.1, 0)
[node name="ShipHelm" parent="." node_paths=PackedStringArray("parent_ship") instance=ExtResource("3_eyiku")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -7.54699)
parent_ship = NodePath("..")

View File

@ -0,0 +1,71 @@
extends RigidBody3D
@export var ship_area: Area3D
@export var ship_helm: ShipHelm
var ship_id: int = 0
var ship_is_piloted: bool = false
var base_turn_speed: float = 1
var top_turn_speed: float = 50.0
var ship_lift_speed: float = 20 # Adjust this value as needed
var acceleration: float = 50
var deceleration: float = acceleration * 0.5
var ship_top_speed: float = 100
var current_speed: float = 0.0
var max_force: float = 1000.0
var piloting_player: Player = null
func _ready():
ship_area.body_entered.connect(_on_area_3d_body_entered)
ship_area.body_exited.connect(_on_area_3d_body_exited)
ship_id = randi_range(1000, 9999)
GameConsole.log_debug("Ship ID: " + str(ship_id))
func _physics_process(delta):
global_rotation.x = lerpf(global_rotation.x, 0, 0.5)
global_rotation.z = lerpf(global_rotation.z, 0, 0.5)
if ship_is_piloted:
var turn_speed = base_turn_speed / max(mass, 1) # changes speeds based on how THICC the ship is
if Input.is_action_pressed("move_left"):
angular_velocity.y += turn_speed
elif Input.is_action_pressed("move_right"):
angular_velocity.y -= turn_speed
if Input.is_action_pressed("jump"):
# Apply an impulse to achieve instantaneous upward velocity
apply_impulse(Vector3.UP * ship_lift_speed)
if Input.is_action_pressed("move_forwards"):
current_speed = min(current_speed + acceleration * delta, ship_top_speed)
else:
current_speed = max(current_speed - deceleration * delta, 0.0)
var desired_velocity = -transform.basis.z * current_speed
var forward_force = (desired_velocity - linear_velocity) * mass
forward_force = forward_force.normalized() * min(forward_force.length(), max_force)
apply_central_force(forward_force)
if Input.is_action_pressed("crouch"):
apply_impulse(Vector3.DOWN * ship_lift_speed)
angular_velocity.y = clamp(angular_velocity.y, -top_turn_speed, top_turn_speed)
func _on_area_3d_body_entered(body):
if body is Player:
piloting_player = body
body.player_entered_ship(global_position, self)
body.set_block_signals(true)
func _on_area_3d_body_exited(body):
if body is Player:
ship_helm.is_being_piloted = false
body.player_exited_ship(global_position, self)
piloting_player = null
body.set_block_signals(false)

View File

@ -1,176 +0,0 @@
[gd_scene load_steps=13 format=3 uid="uid://dhi5myb4u2mij"]
[ext_resource type="Script" path="res://addons/godot_steam_sync/Network/RadomeSteamSync/NetworkPlayerSpawner.gd" id="1_a26tm"]
[ext_resource type="Script" path="res://addons/godot_steam_sync/Network/RadomeSteamSync/SyncNode/RigidBodySync3D.gd" id="2_io2do"]
[sub_resource type="ProceduralSkyMaterial" id="ProceduralSkyMaterial_ilft6"]
sky_horizon_color = Color(0.64625, 0.65575, 0.67075, 1)
ground_horizon_color = Color(0.64625, 0.65575, 0.67075, 1)
[sub_resource type="Sky" id="Sky_ryjhm"]
sky_material = SubResource("ProceduralSkyMaterial_ilft6")
[sub_resource type="Environment" id="Environment_lmp12"]
background_mode = 2
sky = SubResource("Sky_ryjhm")
tonemap_mode = 2
glow_enabled = true
[sub_resource type="BoxMesh" id="BoxMesh_li3io"]
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_r06tq"]
albedo_color = Color(0.321728, 0.321728, 0.321728, 1)
[sub_resource type="ConcavePolygonShape3D" id="ConcavePolygonShape3D_io4rt"]
data = PackedVector3Array(-0.5, 0.5, 0.5, 0.5, 0.5, 0.5, -0.5, -0.5, 0.5, 0.5, 0.5, 0.5, 0.5, -0.5, 0.5, -0.5, -0.5, 0.5, 0.5, 0.5, -0.5, -0.5, 0.5, -0.5, 0.5, -0.5, -0.5, -0.5, 0.5, -0.5, -0.5, -0.5, -0.5, 0.5, -0.5, -0.5, 0.5, 0.5, 0.5, 0.5, 0.5, -0.5, 0.5, -0.5, 0.5, 0.5, 0.5, -0.5, 0.5, -0.5, -0.5, 0.5, -0.5, 0.5, -0.5, 0.5, -0.5, -0.5, 0.5, 0.5, -0.5, -0.5, -0.5, -0.5, 0.5, 0.5, -0.5, -0.5, 0.5, -0.5, -0.5, -0.5, 0.5, 0.5, 0.5, -0.5, 0.5, 0.5, 0.5, 0.5, -0.5, -0.5, 0.5, 0.5, -0.5, 0.5, -0.5, 0.5, 0.5, -0.5, -0.5, -0.5, 0.5, 0.5, -0.5, 0.5, -0.5, -0.5, -0.5, 0.5, -0.5, 0.5, 0.5, -0.5, -0.5, -0.5, -0.5, -0.5)
[sub_resource type="PhysicsMaterial" id="PhysicsMaterial_iltko"]
bounce = 1.0
[sub_resource type="SphereMesh" id="SphereMesh_jxxnq"]
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_cdfuw"]
albedo_color = Color(0.415686, 1, 1, 1)
[sub_resource type="SphereShape3D" id="SphereShape3D_ktxia"]
[node name="Test" type="Node"]
[node name="NetworkPlayerSpawner" type="Node" parent="." node_paths=PackedStringArray("spawn_pos", "players_parent_node")]
script = ExtResource("1_a26tm")
spawn_pos = NodePath("../SpawnPos")
players_parent_node = NodePath("../Players")
[node name="WorldEnvironment" type="WorldEnvironment" parent="."]
environment = SubResource("Environment_lmp12")
[node name="DirectionalLight3D" type="DirectionalLight3D" parent="."]
transform = Transform3D(-0.866023, -0.433016, 0.250001, 0, 0.499998, 0.866027, -0.500003, 0.749999, -0.43301, 0, 0, 0)
shadow_enabled = true
[node name="Players" type="Node3D" parent="."]
[node name="SpawnPos" type="Marker3D" parent="."]
[node name="Level" type="Node3D" parent="."]
[node name="MeshInstance3D" type="MeshInstance3D" parent="Level"]
transform = Transform3D(49.9588, 0, 0, 0, 1, 0, 0, 0, 61.4249, 0, -3.98574, 0)
mesh = SubResource("BoxMesh_li3io")
skeleton = NodePath("../..")
surface_material_override/0 = SubResource("StandardMaterial3D_r06tq")
[node name="StaticBody3D" type="StaticBody3D" parent="Level/MeshInstance3D"]
[node name="CollisionShape3D" type="CollisionShape3D" parent="Level/MeshInstance3D/StaticBody3D"]
shape = SubResource("ConcavePolygonShape3D_io4rt")
[node name="MeshInstance3D6" type="MeshInstance3D" parent="Level"]
transform = Transform3D(-0.506593, 0.999949, 0, -49.9562, -0.0101402, 0, 0, 0, 61.4249, -18.7014, -3.98574, 0)
mesh = SubResource("BoxMesh_li3io")
skeleton = NodePath("../..")
[node name="StaticBody3D" type="StaticBody3D" parent="Level/MeshInstance3D6"]
[node name="CollisionShape3D" type="CollisionShape3D" parent="Level/MeshInstance3D6/StaticBody3D"]
shape = SubResource("ConcavePolygonShape3D_io4rt")
[node name="MeshInstance3D8" type="MeshInstance3D" parent="Level"]
transform = Transform3D(-0.0344473, 0.0679944, 61.2827, -49.9562, -0.0101402, 0, 0.505421, -0.997635, 4.17676, -0.748235, -3.98574, -26.874)
mesh = SubResource("BoxMesh_li3io")
skeleton = NodePath("../..")
[node name="StaticBody3D" type="StaticBody3D" parent="Level/MeshInstance3D8"]
[node name="CollisionShape3D" type="CollisionShape3D" parent="Level/MeshInstance3D8/StaticBody3D"]
shape = SubResource("ConcavePolygonShape3D_io4rt")
[node name="MeshInstance3D9" type="MeshInstance3D" parent="Level"]
transform = Transform3D(-0.0344473, 0.0679944, 61.2827, -49.9562, -0.0101402, 0, 0.505421, -0.997635, 4.17676, -6.63549, -3.98574, 19.7729)
mesh = SubResource("BoxMesh_li3io")
skeleton = NodePath("../..")
[node name="StaticBody3D" type="StaticBody3D" parent="Level/MeshInstance3D9"]
[node name="CollisionShape3D" type="CollisionShape3D" parent="Level/MeshInstance3D9/StaticBody3D"]
shape = SubResource("ConcavePolygonShape3D_io4rt")
[node name="MeshInstance3D7" type="MeshInstance3D" parent="Level"]
transform = Transform3D(-0.506593, 0.999949, 0, -49.9562, -0.0101402, 0, 0, 0, 61.4249, 12.2278, -3.98574, 0)
mesh = SubResource("BoxMesh_li3io")
skeleton = NodePath("../..")
[node name="StaticBody3D" type="StaticBody3D" parent="Level/MeshInstance3D7"]
[node name="CollisionShape3D" type="CollisionShape3D" parent="Level/MeshInstance3D7/StaticBody3D"]
shape = SubResource("ConcavePolygonShape3D_io4rt")
[node name="Physics" type="Node3D" parent="."]
[node name="RigidBody3D" type="RigidBody3D" parent="Physics"]
physics_interpolation_mode = 1
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.20984, 0)
collision_layer = 4
collision_mask = 7
physics_material_override = SubResource("PhysicsMaterial_iltko")
[node name="MeshInstance3D" type="MeshInstance3D" parent="Physics/RigidBody3D"]
mesh = SubResource("SphereMesh_jxxnq")
surface_material_override/0 = SubResource("StandardMaterial3D_cdfuw")
[node name="CollisionShape3D" type="CollisionShape3D" parent="Physics/RigidBody3D"]
shape = SubResource("SphereShape3D_ktxia")
[node name="RigidBodySync3D" type="Node" parent="Physics/RigidBody3D"]
script = ExtResource("2_io2do")
[node name="RigidBody3D2" type="RigidBody3D" parent="Physics"]
physics_interpolation_mode = 1
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -3.5851, 1.20984, -2.08695)
collision_layer = 4
collision_mask = 7
physics_material_override = SubResource("PhysicsMaterial_iltko")
[node name="MeshInstance3D" type="MeshInstance3D" parent="Physics/RigidBody3D2"]
mesh = SubResource("SphereMesh_jxxnq")
surface_material_override/0 = SubResource("StandardMaterial3D_cdfuw")
[node name="CollisionShape3D" type="CollisionShape3D" parent="Physics/RigidBody3D2"]
shape = SubResource("SphereShape3D_ktxia")
[node name="RigidBodySync3D" type="Node" parent="Physics/RigidBody3D2"]
script = ExtResource("2_io2do")
[node name="RigidBody3D3" type="RigidBody3D" parent="Physics"]
physics_interpolation_mode = 1
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.84777, 1.20984, 4.17028)
collision_layer = 4
collision_mask = 7
physics_material_override = SubResource("PhysicsMaterial_iltko")
[node name="MeshInstance3D" type="MeshInstance3D" parent="Physics/RigidBody3D3"]
mesh = SubResource("SphereMesh_jxxnq")
surface_material_override/0 = SubResource("StandardMaterial3D_cdfuw")
[node name="CollisionShape3D" type="CollisionShape3D" parent="Physics/RigidBody3D3"]
shape = SubResource("SphereShape3D_ktxia")
[node name="RigidBodySync3D" type="Node" parent="Physics/RigidBody3D3"]
script = ExtResource("2_io2do")
[node name="RigidBody3D4" type="RigidBody3D" parent="Physics"]
physics_interpolation_mode = 1
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.84777, 1.8173, -2.41229)
collision_layer = 4
collision_mask = 7
physics_material_override = SubResource("PhysicsMaterial_iltko")
[node name="MeshInstance3D" type="MeshInstance3D" parent="Physics/RigidBody3D4"]
mesh = SubResource("SphereMesh_jxxnq")
surface_material_override/0 = SubResource("StandardMaterial3D_cdfuw")
[node name="CollisionShape3D" type="CollisionShape3D" parent="Physics/RigidBody3D4"]
shape = SubResource("SphereShape3D_ktxia")
[node name="RigidBodySync3D" type="Node" parent="Physics/RigidBody3D4"]
script = ExtResource("2_io2do")

View File

@ -1,49 +0,0 @@
@tool
extends Node
# This does not effect runtime yet but will in the future.
@export_category("Controller Editor Module")
@export_range(-360.0, 360.0, 0.01, "or_greater", "or_less") var head_y_rotation : float = 0.0:
set(new_rotation):
if HEAD:
head_y_rotation = new_rotation
HEAD.rotation.y = deg_to_rad(head_y_rotation)
update_configuration_warnings()
@export_range(-90.0, 90.0, 0.01, "or_greater", "or_less") var head_x_rotation : float = 0.0:
set(new_rotation):
if HEAD:
head_x_rotation = new_rotation
HEAD.rotation.x = deg_to_rad(head_x_rotation)
update_configuration_warnings()
@export_group("Nodes")
@export var CHARACTER : CharacterBody3D
@export var head_path : String = "Head" # Relative to the parent node
#@export var CAMERA : Camera3D
#@export var HEADBOB_ANIMATION : AnimationPlayer
#@export var JUMP_ANIMATION : AnimationPlayer
#@export var CROUCH_ANIMATION : AnimationPlayer
#@export var COLLISION_MESH : CollisionShape3D
@onready var HEAD = get_node("../" + head_path)
func _ready():
if !Engine.is_editor_hint():
print("not editor")
HEAD.rotation.y = deg_to_rad(head_y_rotation)
HEAD.rotation.x = deg_to_rad(head_x_rotation)
func _get_configuration_warnings():
var warnings = []
if head_y_rotation > 360:
warnings.append("The head rotation is greater than 360")
if head_y_rotation < -360:
warnings.append("The head rotation is less than -360")
# Returning an empty array gives no warnings
return warnings

View File

@ -1,854 +0,0 @@
[gd_scene load_steps=22 format=3 uid="uid://cc1m2a1obsyn4"]
[ext_resource type="Script" path="res://godotsteam_sync_example/fpc/EditorModule.gd" id="3_v3ckk"]
[ext_resource type="Script" path="res://godotsteam_sync_example/fpc/debug.gd" id="3_x1wcc"]
[ext_resource type="Script" path="res://addons/godot_steam_sync/Network/RadomeSteamSync/SyncNode/TransformSync3D.gd" id="4_ch187"]
[sub_resource type="GDScript" id="GDScript_r0lhh"]
script/source = "
# COPYRIGHT Colormatic Studios
# MIT licence
# Quality Godot First Person Controller v2
extends CharacterBody3D
var IS_OWNER : bool = false
func make_owner():
IS_OWNER = true
$Head/Camera.current = true
## The settings for the character's movement and feel.
@export_category(\"Character\")
## The speed that the character moves at without crouching or sprinting.
@export var base_speed : float = 3.0
## The speed that the character moves at when sprinting.
@export var sprint_speed : float = 6.0
## The speed that the character moves at when crouching.
@export var crouch_speed : float = 1.0
## How fast the character speeds up and slows down when Motion Smoothing is on.
@export var acceleration : float = 10.0
## How high the player jumps.
@export var jump_velocity : float = 4.5
## How far the player turns when the mouse is moved.
@export var mouse_sensitivity : float = 0.1
## Invert the Y input for mouse and joystick
@export var invert_mouse_y : bool = false # Possibly add an invert mouse X in the future
## Wether the player can use movement inputs. Does not stop outside forces or jumping. See Jumping Enabled.
@export var immobile : bool = false
## The reticle file to import at runtime. By default are in res://addons/fpc/reticles/. Set to an empty string to remove.
@export_file var default_reticle
@export_group(\"Nodes\")
## The node that holds the camera. This is rotated instead of the camera for mouse input.
@export var HEAD : Node3D
@export var CAMERA : Camera3D
@export var HEADBOB_ANIMATION : AnimationPlayer
@export var JUMP_ANIMATION : AnimationPlayer
@export var CROUCH_ANIMATION : AnimationPlayer
@export var COLLISION_MESH : CollisionShape3D
@export_group(\"Controls\")
# We are using UI controls because they are built into Godot Engine so they can be used right away
@export var JUMP : String = \"ui_accept\"
@export var LEFT : String = \"ui_left\"
@export var RIGHT : String = \"ui_right\"
@export var FORWARD : String = \"ui_up\"
@export var BACKWARD : String = \"ui_down\"
## By default this does not pause the game, but that can be changed in _process.
@export var PAUSE : String = \"ui_cancel\"
@export var CROUCH : String = \"crouch\"
@export var SPRINT : String = \"sprint\"
# Uncomment if you want controller support
#@export var controller_sensitivity : float = 0.035
#@export var LOOK_LEFT : String = \"look_left\"
#@export var LOOK_RIGHT : String = \"look_right\"
#@export var LOOK_UP : String = \"look_up\"
#@export var LOOK_DOWN : String = \"look_down\"
@export_group(\"Feature Settings\")
## Enable or disable jumping. Useful for restrictive storytelling environments.
@export var jumping_enabled : bool = true
## Wether the player can move in the air or not.
@export var in_air_momentum : bool = true
## Smooths the feel of walking.
@export var motion_smoothing : bool = true
@export var sprint_enabled : bool = true
@export var crouch_enabled : bool = true
@export_enum(\"Hold to Crouch\", \"Toggle Crouch\") var crouch_mode : int = 0
@export_enum(\"Hold to Sprint\", \"Toggle Sprint\") var sprint_mode : int = 0
## Wether sprinting should effect FOV.
@export var dynamic_fov : bool = true
## If the player holds down the jump button, should the player keep hopping.
@export var continuous_jumping : bool = true
## Enables the view bobbing animation.
@export var view_bobbing : bool = true
## Enables an immersive animation when the player jumps and hits the ground.
@export var jump_animation : bool = true
## This determines wether the player can use the pause button, not wether the game will actually pause.
@export var pausing_enabled : bool = true
## Use with caution.
@export var gravity_enabled : bool = true
# Member variables
var speed : float = base_speed
var current_speed : float = 0.0
# States: normal, crouching, sprinting
var state : String = \"normal\"
var low_ceiling : bool = false # This is for when the cieling is too low and the player needs to crouch.
var was_on_floor : bool = true # Was the player on the floor last frame (for landing animation)
# The reticle should always have a Control node as the root
var RETICLE : Control
# Get the gravity from the project settings to be synced with RigidBody nodes
var gravity : float = ProjectSettings.get_setting(\"physics/3d/default_gravity\") # Don't set this as a const, see the gravity section in _physics_process
# Stores mouse input for rotating the camera in the phyhsics process
var mouseInput : Vector2 = Vector2(0,0)
func _ready():
if IS_OWNER:
#It is safe to comment this line if your game doesn't start with the mouse captured
Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
# If the controller is rotated in a certain direction for game design purposes, redirect this rotation into the head.
HEAD.rotation.y = rotation.y
rotation.y = 0
if default_reticle:
change_reticle(default_reticle)
# Reset the camera position
# If you want to change the default head height, change these animations.
HEADBOB_ANIMATION.play(\"RESET\")
JUMP_ANIMATION.play(\"RESET\")
CROUCH_ANIMATION.play(\"RESET\")
check_controls()
func check_controls(): # If you add a control, you might want to add a check for it here.
# The actions are being disabled so the engine doesn't halt the entire project in debug mode
if IS_OWNER:
if !InputMap.has_action(JUMP):
push_error(\"No control mapped for jumping. Please add an input map control. Disabling jump.\")
jumping_enabled = false
if !InputMap.has_action(LEFT):
push_error(\"No control mapped for move left. Please add an input map control. Disabling movement.\")
immobile = true
if !InputMap.has_action(RIGHT):
push_error(\"No control mapped for move right. Please add an input map control. Disabling movement.\")
immobile = true
if !InputMap.has_action(FORWARD):
push_error(\"No control mapped for move forward. Please add an input map control. Disabling movement.\")
immobile = true
if !InputMap.has_action(BACKWARD):
push_error(\"No control mapped for move backward. Please add an input map control. Disabling movement.\")
immobile = true
if !InputMap.has_action(PAUSE):
push_error(\"No control mapped for pause. Please add an input map control. Disabling pausing.\")
pausing_enabled = false
if !InputMap.has_action(CROUCH):
push_error(\"No control mapped for crouch. Please add an input map control. Disabling crouching.\")
crouch_enabled = false
if !InputMap.has_action(SPRINT):
push_error(\"No control mapped for sprint. Please add an input map control. Disabling sprinting.\")
sprint_enabled = false
func change_reticle(reticle): # Yup, this function is kinda strange
if IS_OWNER:
if RETICLE:
RETICLE.queue_free()
RETICLE = load(reticle).instantiate()
RETICLE.character = self
$UserInterface.add_child(RETICLE)
func _physics_process(delta):
if IS_OWNER:
# Big thanks to github.com/LorenzoAncora for the concept of the improved debug values
current_speed = Vector3.ZERO.distance_to(get_real_velocity())
$UserInterface/DebugPanel.add_property(\"Speed\", snappedf(current_speed, 0.001), 1)
$UserInterface/DebugPanel.add_property(\"Target speed\", speed, 2)
var cv : Vector3 = get_real_velocity()
var vd : Array[float] = [
snappedf(cv.x, 0.001),
snappedf(cv.y, 0.001),
snappedf(cv.z, 0.001)
]
var readable_velocity : String = \"X: \" + str(vd[0]) + \" Y: \" + str(vd[1]) + \" Z: \" + str(vd[2])
$UserInterface/DebugPanel.add_property(\"Velocity\", readable_velocity, 3)
# Gravity
#gravity = ProjectSettings.get_setting(\"physics/3d/default_gravity\") # If the gravity changes during your game, uncomment this code
if not is_on_floor() and gravity and gravity_enabled:
velocity.y -= gravity * delta
handle_jumping()
var input_dir = Vector2.ZERO
if !immobile: # Immobility works by interrupting user input, so other forces can still be applied to the player
input_dir = Input.get_vector(LEFT, RIGHT, FORWARD, BACKWARD)
handle_movement(delta, input_dir)
handle_head_rotation()
# The player is not able to stand up if the ceiling is too low
low_ceiling = $CrouchCeilingDetection.is_colliding()
handle_state(input_dir)
if dynamic_fov: # This may be changed to an AnimationPlayer
update_camera_fov()
if view_bobbing:
headbob_animation(input_dir)
if jump_animation:
if !was_on_floor and is_on_floor(): # The player just landed
match randi() % 2: #TODO: Change this to detecting velocity direction
0:
JUMP_ANIMATION.play(\"land_left\", 0.25)
1:
JUMP_ANIMATION.play(\"land_right\", 0.25)
was_on_floor = is_on_floor() # This must always be at the end of physics_process
func handle_jumping():
if IS_OWNER:
if jumping_enabled:
if continuous_jumping: # Hold down the jump button
if Input.is_action_pressed(JUMP) and is_on_floor() and !low_ceiling:
if jump_animation:
JUMP_ANIMATION.play(\"jump\", 0.25)
velocity.y += jump_velocity # Adding instead of setting so jumping on slopes works properly
else:
if Input.is_action_just_pressed(JUMP) and is_on_floor() and !low_ceiling:
if jump_animation:
JUMP_ANIMATION.play(\"jump\", 0.25)
velocity.y += jump_velocity
func handle_movement(delta, input_dir):
if IS_OWNER:
var direction = input_dir.rotated(-HEAD.rotation.y)
direction = Vector3(direction.x, 0, direction.y)
move_and_slide()
if in_air_momentum:
if is_on_floor():
if motion_smoothing:
velocity.x = lerp(velocity.x, direction.x * speed, acceleration * delta)
velocity.z = lerp(velocity.z, direction.z * speed, acceleration * delta)
else:
velocity.x = direction.x * speed
velocity.z = direction.z * speed
else:
if motion_smoothing:
velocity.x = lerp(velocity.x, direction.x * speed, acceleration * delta)
velocity.z = lerp(velocity.z, direction.z * speed, acceleration * delta)
else:
velocity.x = direction.x * speed
velocity.z = direction.z * speed
func handle_head_rotation():
if IS_OWNER:
HEAD.rotation_degrees.y -= mouseInput.x * mouse_sensitivity
if invert_mouse_y:
HEAD.rotation_degrees.x -= mouseInput.y * mouse_sensitivity * -1.0
else:
HEAD.rotation_degrees.x -= mouseInput.y * mouse_sensitivity
# Uncomment for controller support
#var controller_view_rotation = Input.get_vector(LOOK_DOWN, LOOK_UP, LOOK_RIGHT, LOOK_LEFT) * controller_sensitivity # These are inverted because of the nature of 3D rotation.
#HEAD.rotation.x += controller_view_rotation.x
#if invert_mouse_y:
#HEAD.rotation.y += controller_view_rotation.y * -1.0
#else:
#HEAD.rotation.y += controller_view_rotation.y
mouseInput = Vector2(0,0)
HEAD.rotation.x = clamp(HEAD.rotation.x, deg_to_rad(-90), deg_to_rad(90))
func handle_state(moving):
if IS_OWNER:
if sprint_enabled:
if sprint_mode == 0:
if Input.is_action_pressed(SPRINT) and state != \"crouching\":
if moving:
if state != \"sprinting\":
enter_sprint_state()
else:
if state == \"sprinting\":
enter_normal_state()
elif state == \"sprinting\":
enter_normal_state()
elif sprint_mode == 1:
if moving:
# If the player is holding sprint before moving, handle that cenerio
if Input.is_action_pressed(SPRINT) and state == \"normal\":
enter_sprint_state()
if Input.is_action_just_pressed(SPRINT):
match state:
\"normal\":
enter_sprint_state()
\"sprinting\":
enter_normal_state()
elif state == \"sprinting\":
enter_normal_state()
if crouch_enabled:
if crouch_mode == 0:
if Input.is_action_pressed(CROUCH) and state != \"sprinting\":
if state != \"crouching\":
enter_crouch_state()
elif state == \"crouching\" and !$CrouchCeilingDetection.is_colliding():
enter_normal_state()
elif crouch_mode == 1:
if Input.is_action_just_pressed(CROUCH):
match state:
\"normal\":
enter_crouch_state()
\"crouching\":
if !$CrouchCeilingDetection.is_colliding():
enter_normal_state()
# Any enter state function should only be called once when you want to enter that state, not every frame.
func enter_normal_state():
if IS_OWNER:
#print(\"entering normal state\")
var prev_state = state
if prev_state == \"crouching\":
CROUCH_ANIMATION.play_backwards(\"crouch\")
state = \"normal\"
speed = base_speed
func enter_crouch_state():
if IS_OWNER:
#print(\"entering crouch state\")
var prev_state = state
state = \"crouching\"
speed = crouch_speed
CROUCH_ANIMATION.play(\"crouch\")
func enter_sprint_state():
if IS_OWNER:
#print(\"entering sprint state\")
var prev_state = state
if prev_state == \"crouching\":
CROUCH_ANIMATION.play_backwards(\"crouch\")
state = \"sprinting\"
speed = sprint_speed
func update_camera_fov():
if IS_OWNER:
if state == \"sprinting\":
CAMERA.fov = lerp(CAMERA.fov, 85.0, 0.3)
else:
CAMERA.fov = lerp(CAMERA.fov, 75.0, 0.3)
func headbob_animation(moving):
if IS_OWNER:
if moving and is_on_floor():
var use_headbob_animation : String
match state:
\"normal\",\"crouching\":
use_headbob_animation = \"walk\"
\"sprinting\":
use_headbob_animation = \"sprint\"
var was_playing : bool = false
if HEADBOB_ANIMATION.current_animation == use_headbob_animation:
was_playing = true
HEADBOB_ANIMATION.play(use_headbob_animation, 0.25)
HEADBOB_ANIMATION.speed_scale = (current_speed / base_speed) * 1.75
if !was_playing:
HEADBOB_ANIMATION.seek(float(randi() % 2)) # Randomize the initial headbob direction
# Let me explain that piece of code because it looks like it does the opposite of what it actually does.
# The headbob animation has two starting positions. One is at 0 and the other is at 1.
# randi() % 2 returns either 0 or 1, and so the animation randomly starts at one of the starting positions.
# This code is extremely performant but it makes no sense.
else:
if HEADBOB_ANIMATION.current_animation == \"sprint\" or HEADBOB_ANIMATION.current_animation == \"walk\":
HEADBOB_ANIMATION.speed_scale = 1
HEADBOB_ANIMATION.play(\"RESET\", 1)
func _process(delta):
if IS_OWNER:
$UserInterface/DebugPanel.add_property(\"FPS\", Performance.get_monitor(Performance.TIME_FPS), 0)
var status : String = state
if !is_on_floor():
status += \" in the air\"
$UserInterface/DebugPanel.add_property(\"State\", status, 4)
if pausing_enabled:
if Input.is_action_just_pressed(PAUSE):
# You may want another node to handle pausing, because this player may get paused too.
match Input.mouse_mode:
Input.MOUSE_MODE_CAPTURED:
Input.mouse_mode = Input.MOUSE_MODE_VISIBLE
#get_tree().paused = false
Input.MOUSE_MODE_VISIBLE:
Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
#get_tree().paused = false
func _unhandled_input(event : InputEvent):
if IS_OWNER:
if event is InputEventMouseMotion and Input.mouse_mode == Input.MOUSE_MODE_CAPTURED:
mouseInput.x += event.relative.x
mouseInput.y += event.relative.y
# Toggle debug menu
elif event is InputEventKey:
if event.is_released():
# Where we're going, we don't need InputMap
if event.keycode == 4194338: # F7
$UserInterface/DebugPanel.visible = !$UserInterface/DebugPanel.visible
"
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_kp17n"]
albedo_color = Color(0.909804, 0.596078, 0, 1)
clearcoat_enabled = true
clearcoat_roughness = 0.2
[sub_resource type="CapsuleMesh" id="CapsuleMesh_jw1de"]
material = SubResource("StandardMaterial3D_kp17n")
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_uy03j"]
[sub_resource type="Animation" id="Animation_j8cx7"]
resource_name = "RESET"
length = 0.001
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath("Mesh:scale")
tracks/0/interp = 2
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 0,
"values": [Vector3(1, 1, 1)]
}
tracks/1/type = "value"
tracks/1/imported = false
tracks/1/enabled = true
tracks/1/path = NodePath("Collision:scale")
tracks/1/interp = 2
tracks/1/loop_wrap = true
tracks/1/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 0,
"values": [Vector3(1, 1, 1)]
}
tracks/2/type = "value"
tracks/2/imported = false
tracks/2/enabled = true
tracks/2/path = NodePath("Mesh:position")
tracks/2/interp = 2
tracks/2/loop_wrap = true
tracks/2/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 0,
"values": [Vector3(0, 1, 0)]
}
tracks/3/type = "value"
tracks/3/imported = false
tracks/3/enabled = true
tracks/3/path = NodePath("Collision:position")
tracks/3/interp = 2
tracks/3/loop_wrap = true
tracks/3/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 0,
"values": [Vector3(0, 1, 0)]
}
tracks/4/type = "value"
tracks/4/imported = false
tracks/4/enabled = true
tracks/4/path = NodePath("Head:position")
tracks/4/interp = 2
tracks/4/loop_wrap = true
tracks/4/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 0,
"values": [Vector3(0, 1.5, 0)]
}
[sub_resource type="Animation" id="Animation_5ec5e"]
resource_name = "crouch"
length = 0.2
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath("Mesh:scale")
tracks/0/interp = 2
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(0, 0.2),
"transitions": PackedFloat32Array(1, 1),
"update": 0,
"values": [Vector3(1, 1, 1), Vector3(1, 0.75, 1)]
}
tracks/1/type = "value"
tracks/1/imported = false
tracks/1/enabled = true
tracks/1/path = NodePath("Collision:scale")
tracks/1/interp = 2
tracks/1/loop_wrap = true
tracks/1/keys = {
"times": PackedFloat32Array(0, 0.2),
"transitions": PackedFloat32Array(1, 1),
"update": 0,
"values": [Vector3(1, 1, 1), Vector3(1, 0.75, 1)]
}
tracks/2/type = "value"
tracks/2/imported = false
tracks/2/enabled = true
tracks/2/path = NodePath("Mesh:position")
tracks/2/interp = 2
tracks/2/loop_wrap = true
tracks/2/keys = {
"times": PackedFloat32Array(0, 0.2),
"transitions": PackedFloat32Array(1, 1),
"update": 0,
"values": [Vector3(0, 1, 0), Vector3(0, 0.75, 0)]
}
tracks/3/type = "value"
tracks/3/imported = false
tracks/3/enabled = true
tracks/3/path = NodePath("Collision:position")
tracks/3/interp = 2
tracks/3/loop_wrap = true
tracks/3/keys = {
"times": PackedFloat32Array(0, 0.2),
"transitions": PackedFloat32Array(1, 1),
"update": 0,
"values": [Vector3(0, 1, 0), Vector3(0, 0.75, 0)]
}
tracks/4/type = "value"
tracks/4/imported = false
tracks/4/enabled = true
tracks/4/path = NodePath("Head:position")
tracks/4/interp = 2
tracks/4/loop_wrap = true
tracks/4/keys = {
"times": PackedFloat32Array(0, 0.2),
"transitions": PackedFloat32Array(1, 1),
"update": 0,
"values": [Vector3(0, 1.5, 0), Vector3(0, 1.12508, 0)]
}
[sub_resource type="AnimationLibrary" id="AnimationLibrary_5e5t5"]
_data = {
"RESET": SubResource("Animation_j8cx7"),
"crouch": SubResource("Animation_5ec5e")
}
[sub_resource type="Animation" id="Animation_gh776"]
resource_name = "RESET"
length = 0.001
loop_mode = 1
tracks/0/type = "bezier"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath("Camera:position:x")
tracks/0/interp = 1
tracks/0/loop_wrap = true
tracks/0/keys = {
"handle_modes": PackedInt32Array(0),
"points": PackedFloat32Array(0, -0.25, 0, 0.25, 0),
"times": PackedFloat32Array(0)
}
tracks/1/type = "bezier"
tracks/1/imported = false
tracks/1/enabled = true
tracks/1/path = NodePath("Camera:position:y")
tracks/1/interp = 1
tracks/1/loop_wrap = true
tracks/1/keys = {
"handle_modes": PackedInt32Array(0),
"points": PackedFloat32Array(0, -0.25, 0, 0.25, 0),
"times": PackedFloat32Array(0)
}
[sub_resource type="Animation" id="Animation_8ku67"]
resource_name = "sprint"
length = 2.0
loop_mode = 1
tracks/0/type = "bezier"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath("Camera:position:x")
tracks/0/interp = 1
tracks/0/loop_wrap = true
tracks/0/keys = {
"handle_modes": PackedInt32Array(0, 1, 0, 1, 0),
"points": PackedFloat32Array(0.06, -0.25, 0, 0.25, -0.01, 0, 0, 0, 0, 0, -0.06, -0.25, 0.01, 0.25, 0.01, 0, 0, 0, 0, 0, 0.06, -0.25, -0.01, 0.25, 0),
"times": PackedFloat32Array(0, 0.5, 1, 1.5, 2)
}
tracks/1/type = "bezier"
tracks/1/imported = false
tracks/1/enabled = true
tracks/1/path = NodePath("Camera:position:y")
tracks/1/interp = 1
tracks/1/loop_wrap = true
tracks/1/keys = {
"handle_modes": PackedInt32Array(0, 0, 0, 0, 0),
"points": PackedFloat32Array(0.05, -0.25, 0, 0.2, -0.01, 0, -0.2, 0.000186046, 0.2, 0.000186046, 0.05, -0.2, -0.01, 0.2, -0.01, 0, -0.2, 0, 0.2, 0, 0.05, -0.2, -0.01, 0.25, 0),
"times": PackedFloat32Array(0, 0.5, 1, 1.5, 2)
}
[sub_resource type="Animation" id="Animation_lrqmv"]
resource_name = "walk"
length = 2.0
loop_mode = 1
tracks/0/type = "bezier"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath("Camera:position:x")
tracks/0/interp = 1
tracks/0/loop_wrap = true
tracks/0/keys = {
"handle_modes": PackedInt32Array(0, 1, 0, 1, 0),
"points": PackedFloat32Array(0.04, -0.25, 0, 0.25, 0, 0, 0, 0, 0, 0, -0.04, -0.25, 0, 0.25, 0, 0, 0, 0, 0, 0, 0.04, -0.25, 0, 0.25, 0),
"times": PackedFloat32Array(0, 0.5, 1, 1.5, 2)
}
tracks/1/type = "bezier"
tracks/1/imported = false
tracks/1/enabled = true
tracks/1/path = NodePath("Camera:position:y")
tracks/1/interp = 1
tracks/1/loop_wrap = true
tracks/1/keys = {
"handle_modes": PackedInt32Array(0, 0, 0, 0, 0),
"points": PackedFloat32Array(-0.05, -0.25, 0, 0.2, 0.005, 0, -0.2, 0.000186046, 0.2, 0.000186046, -0.05, -0.2, 0.005, 0.2, 0.005, 0, -0.2, 0, 0.2, 0, -0.05, -0.2, 0.005, 0.25, 0),
"times": PackedFloat32Array(0, 0.5, 1, 1.5, 2)
}
[sub_resource type="AnimationLibrary" id="AnimationLibrary_o0unb"]
_data = {
"RESET": SubResource("Animation_gh776"),
"sprint": SubResource("Animation_8ku67"),
"walk": SubResource("Animation_lrqmv")
}
[sub_resource type="Animation" id="Animation_fvvjq"]
length = 0.001
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath("Camera:rotation")
tracks/0/interp = 1
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 0,
"values": [Vector3(0, 0, 0)]
}
tracks/1/type = "value"
tracks/1/imported = false
tracks/1/enabled = true
tracks/1/path = NodePath("Camera:position")
tracks/1/interp = 1
tracks/1/loop_wrap = true
tracks/1/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 0,
"values": [Vector3(0, 0, 0)]
}
[sub_resource type="Animation" id="Animation_s07ye"]
resource_name = "jump"
length = 3.0
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath("Camera:rotation")
tracks/0/interp = 2
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(0, 0.6, 3),
"transitions": PackedFloat32Array(1, 1, 1),
"update": 0,
"values": [Vector3(0, 0, 0), Vector3(0.0349066, 0, 0), Vector3(0, 0, 0)]
}
[sub_resource type="Animation" id="Animation_l1rph"]
resource_name = "land_left"
length = 1.5
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath("Camera:rotation")
tracks/0/interp = 2
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(0, 0.5, 1.5),
"transitions": PackedFloat32Array(1, 1, 1),
"update": 0,
"values": [Vector3(0, 0, 0), Vector3(-0.0349066, 0, 0.0174533), Vector3(0, 0, 0)]
}
tracks/1/type = "value"
tracks/1/imported = false
tracks/1/enabled = true
tracks/1/path = NodePath("Camera:position")
tracks/1/interp = 1
tracks/1/loop_wrap = true
tracks/1/keys = {
"times": PackedFloat32Array(0, 0.5, 1.5),
"transitions": PackedFloat32Array(1, 1, 1),
"update": 0,
"values": [Vector3(0, 0, 0), Vector3(0, -0.1, 0), Vector3(0, 0, 0)]
}
[sub_resource type="Animation" id="Animation_vsknp"]
resource_name = "land_right"
length = 1.5
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath("Camera:rotation")
tracks/0/interp = 2
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(0, 0.5, 1.5),
"transitions": PackedFloat32Array(1, 1, 1),
"update": 0,
"values": [Vector3(0, 0, 0), Vector3(-0.0349066, 0, -0.0174533), Vector3(0, 0, 0)]
}
tracks/1/type = "value"
tracks/1/imported = false
tracks/1/enabled = true
tracks/1/path = NodePath("Camera:position")
tracks/1/interp = 1
tracks/1/loop_wrap = true
tracks/1/keys = {
"times": PackedFloat32Array(0, 0.5, 1.5),
"transitions": PackedFloat32Array(1, 1, 1),
"update": 0,
"values": [Vector3(0, 0, 0), Vector3(0, -0.1, 0), Vector3(0, 0, 0)]
}
[sub_resource type="AnimationLibrary" id="AnimationLibrary_qeg5r"]
_data = {
"RESET": SubResource("Animation_fvvjq"),
"jump": SubResource("Animation_s07ye"),
"land_left": SubResource("Animation_l1rph"),
"land_right": SubResource("Animation_vsknp")
}
[sub_resource type="Theme" id="Theme_wdf0f"]
MarginContainer/constants/margin_bottom = 10
MarginContainer/constants/margin_left = 10
MarginContainer/constants/margin_right = 10
MarginContainer/constants/margin_top = 10
[sub_resource type="SphereShape3D" id="SphereShape3D_k4wwl"]
[node name="Character" type="CharacterBody3D" node_paths=PackedStringArray("HEAD", "CAMERA", "HEADBOB_ANIMATION", "JUMP_ANIMATION", "CROUCH_ANIMATION", "COLLISION_MESH")]
collision_layer = 2
collision_mask = 3
script = SubResource("GDScript_r0lhh")
default_reticle = "res://godotsteam_sync_example/fpc/reticles/reticle_1.tscn"
HEAD = NodePath("Head")
CAMERA = NodePath("Head/Camera")
HEADBOB_ANIMATION = NodePath("Head/HeadbobAnimation")
JUMP_ANIMATION = NodePath("Head/JumpAnimation")
CROUCH_ANIMATION = NodePath("CrouchAnimation")
COLLISION_MESH = NodePath("Collision")
JUMP = "jump"
LEFT = "left"
RIGHT = "right"
FORWARD = "forward"
BACKWARD = "backward"
PAUSE = "pause"
[node name="Mesh" type="MeshInstance3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0)
mesh = SubResource("CapsuleMesh_jw1de")
[node name="Collision" type="CollisionShape3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0)
shape = SubResource("CapsuleShape3D_uy03j")
[node name="CrouchAnimation" type="AnimationPlayer" parent="."]
libraries = {
"": SubResource("AnimationLibrary_5e5t5")
}
[node name="Head" type="Node3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.5, 0)
[node name="Camera" type="Camera3D" parent="Head"]
[node name="HeadbobAnimation" type="AnimationPlayer" parent="Head"]
libraries = {
"": SubResource("AnimationLibrary_o0unb")
}
blend_times = [&"RESET", &"RESET", 0.5, &"RESET", &"walk", 0.5, &"walk", &"RESET", 0.5]
[node name="JumpAnimation" type="AnimationPlayer" parent="Head"]
libraries = {
"": SubResource("AnimationLibrary_qeg5r")
}
speed_scale = 4.0
[node name="UserInterface" type="Control" parent="."]
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
mouse_filter = 1
[node name="DebugPanel" type="PanelContainer" parent="UserInterface"]
visible = false
layout_mode = 0
offset_left = 10.0
offset_top = 10.0
offset_right = 453.0
offset_bottom = 50.0
theme = SubResource("Theme_wdf0f")
script = ExtResource("3_x1wcc")
[node name="MarginContainer" type="MarginContainer" parent="UserInterface/DebugPanel"]
layout_mode = 2
[node name="VBoxContainer" type="VBoxContainer" parent="UserInterface/DebugPanel/MarginContainer"]
layout_mode = 2
[node name="CrouchCeilingDetection" type="ShapeCast3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0)
shape = SubResource("SphereShape3D_k4wwl")
target_position = Vector3(0, 0.5, 0)
[node name="EditorModule" type="Node" parent="."]
script = ExtResource("3_v3ckk")
[node name="TransformSync3D" type="Node" parent="." node_paths=PackedStringArray("object_player")]
script = ExtResource("4_ch187")
object_player = NodePath("..")

View File

@ -1,18 +0,0 @@
extends PanelContainer
func _process(delta):
if visible:
pass
func add_property(title : String, value, order : int): # This can either be called once for a static property or called every frame for a dynamic property
var target
target = $MarginContainer/VBoxContainer.find_child(title, true, false) # I have no idea what true and false does here, the function should be more specific
if !target:
target = Label.new() # Debug lines are of type Label
$MarginContainer/VBoxContainer.add_child(target)
target.name = title
target.text = title + ": " + str(value)
elif visible:
target.text = title + ": " + str(value)
$MarginContainer/VBoxContainer.move_child(target, order)

View File

@ -1,37 +0,0 @@
[gd_scene load_steps=2 format=3 uid="uid://coqpusufa8a6k"]
[sub_resource type="GDScript" id="GDScript_10f85"]
script/source = "extends CenterContainer
@export_category(\"Reticle\")
@export_group(\"Nodes\")
@export var character : CharacterBody3D
@export_group(\"Settings\")
@export var dot_size : int = 1
@export var dot_color : Color = Color.WHITE
func _process(_delta):
if visible: # If the reticle is disabled (not visible), don't bother updating it
update_reticle_settings()
func update_reticle_settings():
$dot.scale.x = dot_size
$dot.scale.y = dot_size
$dot.color = dot_color
"
[node name="Reticle" type="CenterContainer"]
anchors_preset = 8
anchor_left = 0.5
anchor_top = 0.5
anchor_right = 0.5
anchor_bottom = 0.5
grow_horizontal = 2
grow_vertical = 2
script = SubResource("GDScript_10f85")
[node name="dot" type="Polygon2D" parent="."]
polygon = PackedVector2Array(-1, -1, 1, -1, 1, 1, -1, 1)

View File

@ -1,104 +0,0 @@
[gd_scene load_steps=2 format=3 uid="uid://3mij3cjhkwsm"]
[sub_resource type="GDScript" id="GDScript_a8kpl"]
script/source = "extends CenterContainer
@export_category(\"Reticle\")
@export_group(\"Nodes\")
@export var reticle_lines : Array[Line2D]
@export var character : CharacterBody3D
@export_group(\"Animate\")
@export var animated_reticle : bool = true
@export var reticle_speed : float = 0.5
@export var reticle_spread : float = 4.0
@export_group(\"Dot Settings\")
@export var dot_size : int = 1
@export var dot_color : Color = Color.WHITE
@export_group(\"Line Settings\")
@export var line_color : Color = Color.WHITE
@export var line_width : int = 2
@export var line_length : int = 10
@export var line_distance : int = 5
@export_enum(\"None\", \"Round\") var cap_mode : int = 0
func _process(_delta):
if visible: # If the reticle is disabled (not visible), don't bother updating it
update_reticle_settings()
if animated_reticle:
animate_reticle_lines()
func animate_reticle_lines():
var vel = character.get_real_velocity()
var origin = Vector3(0,0,0)
var pos = Vector2(0,0)
var speed = origin.distance_to(vel)
reticle_lines[0].position = lerp(reticle_lines[0].position, pos + Vector2(0, -speed * reticle_spread), reticle_speed)
reticle_lines[1].position = lerp(reticle_lines[1].position, pos + Vector2(-speed * reticle_spread, 0), reticle_speed)
reticle_lines[2].position = lerp(reticle_lines[2].position, pos + Vector2(speed * reticle_spread, 0), reticle_speed)
reticle_lines[3].position = lerp(reticle_lines[3].position, pos + Vector2(0, speed * reticle_spread), reticle_speed)
func update_reticle_settings():
# Dot
$dot.scale.x = dot_size
$dot.scale.y = dot_size
$dot.color = dot_color
# Lines
for line in reticle_lines:
line.default_color = line_color
line.width = line_width
if cap_mode == 0:
line.begin_cap_mode = Line2D.LINE_CAP_NONE
line.end_cap_mode = Line2D.LINE_CAP_NONE
elif cap_mode == 1:
line.begin_cap_mode = Line2D.LINE_CAP_ROUND
line.end_cap_mode = Line2D.LINE_CAP_ROUND
# Please someone find a better way to do this
reticle_lines[0].points[0].y = -line_distance
reticle_lines[0].points[1].y = -line_length - line_distance
reticle_lines[1].points[0].x = -line_distance
reticle_lines[1].points[1].x = -line_length - line_distance
reticle_lines[2].points[0].x = line_distance
reticle_lines[2].points[1].x = line_length + line_distance
reticle_lines[3].points[0].y = line_distance
reticle_lines[3].points[1].y = line_length + line_distance
"
[node name="Reticle" type="CenterContainer" node_paths=PackedStringArray("reticle_lines")]
anchors_preset = 8
anchor_left = 0.5
anchor_top = 0.5
anchor_right = 0.5
anchor_bottom = 0.5
grow_horizontal = 2
grow_vertical = 2
script = SubResource("GDScript_a8kpl")
reticle_lines = [NodePath("top"), NodePath("left"), NodePath("right"), NodePath("bottom")]
[node name="dot" type="Polygon2D" parent="."]
polygon = PackedVector2Array(-1, -1, 1, -1, 1, 1, -1, 1)
[node name="top" type="Line2D" parent="."]
points = PackedVector2Array(0, -5, 0, -15)
width = 2.0
[node name="left" type="Line2D" parent="."]
points = PackedVector2Array(-5, 0, -15, 0)
width = 2.0
[node name="right" type="Line2D" parent="."]
points = PackedVector2Array(5, 0, 15, 0)
width = 2.0
[node name="bottom" type="Line2D" parent="."]
points = PackedVector2Array(0, 5, 0, 15)
width = 2.0

View File

@ -1 +0,0 @@
extends Node

View File

@ -11,16 +11,14 @@ config_version=5
[application] [application]
config/name="Steamforged Skies" config/name="Steamforged Skies"
run/main_scene="res://addons/godot_steam_sync/Lobby/main_menu.tscn" run/main_scene="res://assets/core/networking/scenes/lobby.tscn"
config/features=PackedStringArray("4.3", "Forward Plus") config/features=PackedStringArray("4.3", "Forward Plus")
config/icon="res://assets/icon.png" config/icon="res://assets/icon.png"
[autoload] [autoload]
GameConsole="*res://addons/ingameconsole/GameConsole.tscn" GameConsole="*res://addons/ingameconsole/GameConsole.tscn"
NetworkManager="*res://addons/godot_steam_sync/Network/RadomeSteamSync/NetworkManager.gd" NetworkManager="*res://assets/core/networking/scripts/NetworkManager.gd"
P2P="*res://addons/godot_steam_sync/Network/RadomeSteamSync/P2P.gd"
SceneManager="*res://assets/core/networking/scripts/SceneManager.gd"
[debug] [debug]
@ -38,7 +36,7 @@ project/assembly_name="Steamforged Skies"
[editor_plugins] [editor_plugins]
enabled=PackedStringArray("res://addons/godot_steam_sync/plugin.cfg", "res://addons/ingameconsole/plugin.cfg") enabled=PackedStringArray("res://addons/ingameconsole/plugin.cfg")
[input] [input]