Initial push
This commit is contained in:
commit
3240f07946
335 changed files with 11248 additions and 0 deletions
246
Scripts/Chat/chat_menu.gd
Normal file
246
Scripts/Chat/chat_menu.gd
Normal file
|
|
@ -0,0 +1,246 @@
|
|||
class_name ChatMenu
|
||||
extends Control
|
||||
|
||||
|
||||
#region Onready Variables
|
||||
|
||||
@onready var scroll_container = $AspectRatioContainer/MarginContainer/VBoxContainer/ScrollContainer
|
||||
@onready var command_text_edit = $AspectRatioContainer/MarginContainer/VBoxContainer/CommandScrollContainer/CommandTextEdit
|
||||
@onready var message_container = $AspectRatioContainer/MarginContainer/VBoxContainer/ScrollContainer/MessageContainer
|
||||
@onready var visible_timer = $VisibleTimer
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Variables
|
||||
|
||||
var opened : bool = false
|
||||
var clear_command_text : bool = false
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Signals
|
||||
|
||||
signal chat_opened()
|
||||
signal spawn_item(item_name : String, x : String, y : String, z : String)
|
||||
signal lobby_move(x : String, z : String)
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Godot Functions
|
||||
|
||||
func _ready() -> void:
|
||||
hide()
|
||||
opened = false
|
||||
command_text_edit.gui_input.connect(_command_text_edit_gui_input)
|
||||
visible_timer.timeout.connect(hide)
|
||||
|
||||
func _process(_delta : float):
|
||||
if clear_command_text == true:
|
||||
command_text_edit.text = ""
|
||||
clear_command_text = false
|
||||
|
||||
if opened == true:
|
||||
if Input.is_action_just_pressed("pause"):
|
||||
remove_focus()
|
||||
visible_timer.start()
|
||||
return
|
||||
|
||||
if Input.is_action_just_pressed("open_chat"):
|
||||
visible_timer.stop()
|
||||
chat_opened.emit()
|
||||
show()
|
||||
focus()
|
||||
|
||||
if Input.is_action_just_pressed("open_chat_as_command"):
|
||||
visible_timer.stop()
|
||||
command_text_edit.text = "/"
|
||||
chat_opened.emit()
|
||||
show()
|
||||
focus()
|
||||
command_text_edit.set_caret_column(1, false, 0)
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Public Functions
|
||||
|
||||
func focus():
|
||||
mouse_filter = Control.MOUSE_FILTER_STOP
|
||||
opened = true
|
||||
Global.in_menu = true
|
||||
command_text_edit.grab_focus()
|
||||
|
||||
func remove_focus():
|
||||
mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
opened = false
|
||||
command_text_edit.release_focus()
|
||||
Global.in_menu = false
|
||||
|
||||
func send_message(message : String, keep_focus : bool, label_color : Color = Color(1, 1, 1, 1)):
|
||||
visible_timer.stop()
|
||||
show()
|
||||
var message_label : Label = Label.new()
|
||||
message_label.text = message
|
||||
message_label.label_settings = LabelSettings.new()
|
||||
message_label.label_settings.font_color = label_color
|
||||
message_label.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
|
||||
message_container.add_child(message_label)
|
||||
|
||||
if keep_focus == false:
|
||||
remove_focus()
|
||||
visible_timer.start()
|
||||
|
||||
get_tree().create_timer(0.01).timeout.connect(
|
||||
func() -> void:
|
||||
scroll_container.scroll_vertical = scroll_container.get_v_scroll_bar().max_value
|
||||
)
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Signal Functions
|
||||
|
||||
func _command_text_edit_gui_input(event : InputEvent):
|
||||
if event.is_action_pressed("chat_send"):
|
||||
send_message(command_text_edit.text, false)
|
||||
check_command(command_text_edit.text)
|
||||
clear_command_text = true
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region "Private" Functions
|
||||
|
||||
func check_command(command : String):
|
||||
command.strip_edges(true, true)
|
||||
|
||||
if command.begins_with("/") == false:
|
||||
return
|
||||
|
||||
if Global.is_admin == false:
|
||||
send_message("Cannot run command without admin status", false)
|
||||
return
|
||||
|
||||
command = command.lstrip("/")
|
||||
|
||||
# ~ SPAWN ~ #
|
||||
if command.begins_with("spawn ") or command == "spawn":
|
||||
command = command.lstrip("spawn ")
|
||||
command = command.trim_prefix(" ")
|
||||
|
||||
#get the item name and check that it exists
|
||||
var item_next_space : int = command.find(" ")
|
||||
if item_next_space == -1:
|
||||
send_message("Spawn Syntax error, spawn command looks like `spawn <entity_name> x y z`", false, Color(1, 0, 0, 1))
|
||||
return
|
||||
|
||||
var item_name : String = command.substr(0, item_next_space)
|
||||
command = command.lstrip(item_name)
|
||||
command = command.trim_prefix(" ")
|
||||
|
||||
# if EntityResource.ids_by_name.has(item_name) == false:
|
||||
# var entity_names = ""
|
||||
# for key in EntityResource.data:
|
||||
# if EntityResource.data[key].spawnable == false:
|
||||
# continue
|
||||
|
||||
# entity_names += EntityResource.data[key].name + " "
|
||||
|
||||
# send_message("Entity: \"" + item_name + "\" was not found, cannot spawn. Entity List is: " + entity_names, false, Color(1, 0, 0, 1))
|
||||
# return
|
||||
|
||||
#get x
|
||||
item_next_space = command.find(" ")
|
||||
if item_next_space == -1:
|
||||
send_message("Spawn Syntax error, spawn command looks like `spawn <entity_name> x y z`", false, Color(1, 0, 0, 1))
|
||||
return
|
||||
|
||||
var x_name : String = command.substr(0, item_next_space)
|
||||
command = command.lstrip(x_name)
|
||||
command = command.trim_prefix(" ")
|
||||
|
||||
if x_name != "~" and x_name.is_valid_int() == false:
|
||||
send_message("Spawn Syntax error: x value was not ~ or int", false, Color(1, 0, 0, 1))
|
||||
return
|
||||
|
||||
#get y
|
||||
item_next_space = command.find(" ")
|
||||
if item_next_space == -1:
|
||||
send_message("Spawn Syntax error, spawn command looks like `spawn <entity_name> x y z`", false, Color(1, 0, 0, 1))
|
||||
return
|
||||
|
||||
var y_name : String = command.substr(0, item_next_space)
|
||||
command = command.lstrip(y_name)
|
||||
command = command.trim_prefix(" ")
|
||||
|
||||
if y_name != "~" and y_name.is_valid_int() == false:
|
||||
send_message("Spawn Syntax error: y value was not ~ or int", false, Color(1, 0, 0, 1))
|
||||
return
|
||||
|
||||
#check z (which is what is left in command)
|
||||
command = command.trim_prefix(" ")
|
||||
command = command.trim_suffix(" ")
|
||||
if command == "":
|
||||
send_message("Spawn Syntax error, spawn command looks like `spawn <entity_name> x y z`", false, Color(1, 0, 0, 1))
|
||||
|
||||
if command != "~" and command.is_valid_int() == false:
|
||||
send_message("Item Spawn Syntax error: z value was not ~ or int", false, Color(1, 0, 0, 1))
|
||||
return
|
||||
|
||||
#call spawn item
|
||||
spawn_item.emit(item_name, x_name, y_name, command)
|
||||
return
|
||||
|
||||
# ~ LOBBY ~ #
|
||||
if command.begins_with("lobby ") or command == "lobby":
|
||||
command = command.lstrip("lobby ")
|
||||
command = command.trim_prefix(" ")
|
||||
|
||||
#get the type name and check that it exists
|
||||
var type_next_space : int = command.find(" ")
|
||||
if type_next_space == -1:
|
||||
send_message("Lobby Syntax error, lobby command looks like `lobby <action> [args]`", false, Color(1, 0, 0, 1))
|
||||
return
|
||||
|
||||
# ~ move ~ #
|
||||
if command.begins_with("move ") or command == "move":
|
||||
command = command.lstrip("move ")
|
||||
command = command.trim_prefix(" ")
|
||||
|
||||
#error check for if there is no position
|
||||
if command == "":
|
||||
send_message("Lobby Move Syntax error, lobby move command looks like `lobby move x z`", false, Color(1, 0, 0, 1))
|
||||
return
|
||||
|
||||
#get x
|
||||
var position_space : int = command.find(" ")
|
||||
if position_space == -1:
|
||||
send_message("Lobby Move Syntax error, lobby move command looks like `lobby move x z`", false, Color(1, 0, 0, 1))
|
||||
return
|
||||
|
||||
var x_name : String = command.substr(0, position_space)
|
||||
command = command.lstrip(x_name)
|
||||
command = command.trim_prefix(" ")
|
||||
|
||||
if x_name != "~" and x_name.is_valid_int() == false:
|
||||
send_message("Lobby Move Syntax error: x value was not ~ or int", false, Color(1, 0, 0, 1))
|
||||
return
|
||||
|
||||
#check z (which is what is left in command)
|
||||
command = command.trim_prefix(" ")
|
||||
command = command.trim_suffix(" ")
|
||||
if command == "":
|
||||
send_message("Lobby Move Syntax error, lobby move command looks like `lobby move x z`", false, Color(1, 0, 0, 1))
|
||||
|
||||
if command != "~" and command.is_valid_int() == false:
|
||||
send_message("Lobby Move Syntax error: z value was not ~ or int", false, Color(1, 0, 0, 1))
|
||||
return
|
||||
|
||||
#call spawn item
|
||||
lobby_move.emit(x_name, command)
|
||||
return
|
||||
|
||||
#endregion
|
||||
1
Scripts/Chat/chat_menu.gd.uid
Normal file
1
Scripts/Chat/chat_menu.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://c8k0usfm5rdm3
|
||||
5
Scripts/Items/goblet.gd
Normal file
5
Scripts/Items/goblet.gd
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
extends RigidBody3D
|
||||
|
||||
@export var item : Item
|
||||
@onready var interactable : Interactable = $Interactable
|
||||
@onready var is_interactable : bool = true
|
||||
1
Scripts/Items/goblet.gd.uid
Normal file
1
Scripts/Items/goblet.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://bntxwxn6ns5l0
|
||||
5
Scripts/Items/interactable.gd
Normal file
5
Scripts/Items/interactable.gd
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
extends Node3D
|
||||
|
||||
class_name Interactable
|
||||
|
||||
@onready var outline : MeshInstance3D = $outline
|
||||
1
Scripts/Items/interactable.gd.uid
Normal file
1
Scripts/Items/interactable.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://bahmrqvs4pafg
|
||||
60
Scripts/Level/level.gd
Normal file
60
Scripts/Level/level.gd
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
class_name Level
|
||||
extends Node
|
||||
|
||||
var player_scene : PackedScene = preload("res://Scenes/Mobs/character.tscn")
|
||||
|
||||
@export var lobby : Lobby
|
||||
|
||||
var spawnid : int = 0
|
||||
|
||||
func _ready() -> void:
|
||||
spawn_player.rpc_id(1, 1)
|
||||
|
||||
@rpc("any_peer", "call_local")
|
||||
func request_spawn_player(id : int) -> void:
|
||||
#only run on the multiplayer instance
|
||||
if not multiplayer.is_server():
|
||||
return
|
||||
|
||||
#don't spawn an already spawned player
|
||||
if get_node_or_null("Player" + str(id)) != null:
|
||||
return
|
||||
|
||||
spawn_player.rpc_id(1, id)
|
||||
|
||||
@rpc("any_peer", "call_local")
|
||||
func spawn_player(id: int) -> void:
|
||||
var new_player : Player = player_scene.instantiate()
|
||||
|
||||
new_player.name = "Player" + str(id)
|
||||
print("Spawning ID: ", id)
|
||||
add_child(new_player)
|
||||
var spawn_point: Marker3D = lobby.spawnpoints[spawnid]
|
||||
print(spawn_point.global_position)
|
||||
new_player.teleport_player.rpc(spawn_point.global_position, spawn_point.rotation)
|
||||
spawnid += 1
|
||||
|
||||
@rpc("authority", "call_local")
|
||||
func remove_client_from_server(id : int) -> void:
|
||||
var disconnected_player : Player = get_node("Player" + str(id))
|
||||
spawnid = 1
|
||||
remove_child.call_deferred(disconnected_player)
|
||||
disconnected_player.queue_free()
|
||||
|
||||
@rpc("any_peer", "call_local")
|
||||
func disconnect_from_server():
|
||||
remove_players()
|
||||
spawnid = 0
|
||||
# reset map
|
||||
print("Disconnect: ", multiplayer.get_unique_id())
|
||||
request_spawn_player.rpc(1)
|
||||
|
||||
|
||||
|
||||
func remove_players(remove_host : bool = true) -> void:
|
||||
for child in get_children():
|
||||
if child is Player:
|
||||
if !remove_host and child.name == "Player1":
|
||||
continue
|
||||
remove_child(child)
|
||||
child.queue_free()
|
||||
1
Scripts/Level/level.gd.uid
Normal file
1
Scripts/Level/level.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://bsyvwqveefopb
|
||||
5
Scripts/Level/lobby.gd
Normal file
5
Scripts/Level/lobby.gd
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
class_name Lobby
|
||||
extends Node3D
|
||||
|
||||
|
||||
@onready var spawnpoints : Array[Marker3D] = [$spawnpoint1, $spawnpoint2, $spawnpoint3, $spawnpoint4]
|
||||
1
Scripts/Level/lobby.gd.uid
Normal file
1
Scripts/Level/lobby.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://cdc5npqxn0eda
|
||||
33
Scripts/Menu/inventory_menu.gd
Normal file
33
Scripts/Menu/inventory_menu.gd
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
extends Node
|
||||
|
||||
class_name InventoryMenu
|
||||
|
||||
|
||||
@onready var inventory : Inventory
|
||||
@onready var item_list : VBoxContainer = $CanvasLayer/PanelContainer/VBoxContainer/MarginContainer/ScrollContainer/VBoxContainer
|
||||
var item_scene : PackedScene = preload("res://Scenes/Menu/InventoryUiItem.tscn")
|
||||
|
||||
func _ready() -> void:
|
||||
$CanvasLayer.hide()
|
||||
pass
|
||||
|
||||
|
||||
func toggle_inventory() -> bool:
|
||||
var canvas = $CanvasLayer
|
||||
if canvas.visible == true:
|
||||
$CanvasLayer.hide()
|
||||
return false
|
||||
else:
|
||||
update_inventory()
|
||||
$CanvasLayer.show()
|
||||
return true
|
||||
|
||||
func update_inventory():
|
||||
for i in inventory.items:
|
||||
var new_item = item_scene.instantiate()
|
||||
# new_item.set_values(i.item.name, i.item.value, i.item.weight)
|
||||
item_list.add_child(new_item)
|
||||
new_item.set_values(i.item.name, 10, 10)
|
||||
print(i.item.name)
|
||||
print(i)
|
||||
pass
|
||||
1
Scripts/Menu/inventory_menu.gd.uid
Normal file
1
Scripts/Menu/inventory_menu.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://ddwvtegkiite7
|
||||
11
Scripts/Menu/inventory_ui_item.gd
Normal file
11
Scripts/Menu/inventory_ui_item.gd
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
extends Node
|
||||
|
||||
@onready var title : Label = $Name
|
||||
@onready var value : Label = $Value
|
||||
@onready var weight : Label = $Weight
|
||||
|
||||
|
||||
func set_values(new_title : String, new_value : int, new_weight : int) -> void:
|
||||
title.text = new_title
|
||||
value.text = str(new_value)
|
||||
weight.text = str(new_weight)
|
||||
1
Scripts/Menu/inventory_ui_item.gd.uid
Normal file
1
Scripts/Menu/inventory_ui_item.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://bv3glh0xi771m
|
||||
169
Scripts/Menu/lobby_menu.gd
Normal file
169
Scripts/Menu/lobby_menu.gd
Normal file
|
|
@ -0,0 +1,169 @@
|
|||
class_name LobbyMenu
|
||||
extends Node
|
||||
|
||||
|
||||
#region Onready Variables
|
||||
|
||||
@onready var lobby_container : Container = $LobbyContainer
|
||||
@onready var username : LineEdit = $VBoxContainer/Name
|
||||
@onready var lobby_label : Label = $VBoxContainer/HBoxContainer/LobbyLabel
|
||||
@onready var steam_lobby_id_button : Button = $VBoxContainer/HBoxContainer/SteamLobbyIdButton
|
||||
@onready var disconnect_button : Button = $VBoxContainer/HBoxContainer/Disconnect
|
||||
@onready var tab_container : TabContainer = $VBoxContainer/TabContainer
|
||||
|
||||
@onready var steam_tab : Control = $VBoxContainer/TabContainer/Steam
|
||||
@onready var steam_address_entry : LineEdit = $VBoxContainer/TabContainer/Steam/PanelContainer/MarginContainer/VBoxContainer/Address
|
||||
@onready var steam_host_button : Button = $VBoxContainer/TabContainer/Steam/PanelContainer/MarginContainer/VBoxContainer/Host
|
||||
@onready var steam_join_button : Button = $VBoxContainer/TabContainer/Steam/PanelContainer/MarginContainer/VBoxContainer/Join
|
||||
|
||||
@onready var enet_address_entry : LineEdit = $VBoxContainer/TabContainer/ENet/PanelContainer/MarginContainer/VBoxContainer/Address
|
||||
@onready var enet_host_toggle : CheckButton = $VBoxContainer/TabContainer/ENet/PanelContainer/MarginContainer/VBoxContainer/HostToggleContainer/Host
|
||||
@onready var enet_join_button : Button = $VBoxContainer/TabContainer/ENet/PanelContainer/MarginContainer/VBoxContainer/Join
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Variables
|
||||
|
||||
var steam_lobby_id : String = ""
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Signals
|
||||
|
||||
signal disconnect_button_pressed()
|
||||
|
||||
signal steam_host_pressed(new_username : String)
|
||||
signal steam_join_pressed(new_username : String)
|
||||
|
||||
signal enet_host_toggled_on(new_username : String)
|
||||
signal enet_host_toggled_off()
|
||||
signal enet_join_pressed(new_username : String)
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Godot Functions
|
||||
|
||||
func _ready() -> void:
|
||||
#set username to steam username
|
||||
username.text = "username"
|
||||
|
||||
disconnect_button.pressed.connect(_on_disconnet_button_pressed)
|
||||
|
||||
#steam
|
||||
if Global.steam_connected == true:
|
||||
username.text = Steam.getPersonaName()
|
||||
|
||||
steam_lobby_id_button.pressed.connect(_on_steam_lobby_id_button_pressed)
|
||||
steam_host_button.pressed.connect(_on_steam_host_pressed)
|
||||
steam_join_button.pressed.connect(_on_steam_join_pressed)
|
||||
|
||||
#enet
|
||||
enet_host_toggle.toggled.connect(_on_enet_host_toggled)
|
||||
enet_join_button.pressed.connect(_on_enet_join_pressed)
|
||||
|
||||
if Global.steam_connected == false:
|
||||
tab_container.remove_child(steam_tab)
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Public Functions
|
||||
|
||||
func reset_visible() -> void:
|
||||
steam_lobby_id_button.hide()
|
||||
disconnect_button.hide()
|
||||
clear_lobby_text()
|
||||
username.show()
|
||||
|
||||
#steam
|
||||
steam_join_button.show()
|
||||
steam_address_entry.show()
|
||||
steam_host_button.show()
|
||||
|
||||
#enet
|
||||
tab_container.tabs_visible = true
|
||||
tab_container.show()
|
||||
enet_address_entry.show()
|
||||
enet_join_button.show()
|
||||
|
||||
func request_lobby_list() -> void:
|
||||
for child in lobby_container.get_children():
|
||||
child.queue_free()
|
||||
|
||||
Steam.requestLobbyList()
|
||||
|
||||
func set_lobby_text(new_names : Array[String]) -> void:
|
||||
clear_lobby_text()
|
||||
|
||||
for new_name in new_names:
|
||||
var name_label : Label = Label.new()
|
||||
name_label.text = new_name
|
||||
lobby_container.add_child(name_label)
|
||||
|
||||
func clear_lobby_text() -> void:
|
||||
var lobby_container_children = lobby_container.get_children()
|
||||
for child in lobby_container_children:
|
||||
child.free()
|
||||
|
||||
func update_steam_lobby_id_button():
|
||||
steam_lobby_id_button.show()
|
||||
steam_lobby_id = Global.steam_lobby_id
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Signal Functions
|
||||
func _on_disconnet_button_pressed() -> void:
|
||||
disconnect_button_pressed.emit()
|
||||
|
||||
func _on_steam_host_pressed() -> void:
|
||||
steam_host_pressed.emit(username.text)
|
||||
steam_join_button.hide()
|
||||
tab_container.tabs_visible = false
|
||||
steam_address_entry.hide()
|
||||
steam_host_button.hide()
|
||||
username.hide()
|
||||
|
||||
func _on_steam_join_pressed() -> void:
|
||||
Global.steam_lobby_id = steam_address_entry.text
|
||||
steam_join_pressed.emit(username.text)
|
||||
steam_join_button.hide()
|
||||
tab_container.tabs_visible = false
|
||||
steam_address_entry.hide()
|
||||
steam_host_button.hide()
|
||||
username.hide()
|
||||
disconnect_button.show()
|
||||
|
||||
func _on_enet_host_toggled(toggled_on : bool) -> void:
|
||||
if toggled_on:
|
||||
enet_address_entry.hide()
|
||||
enet_join_button.hide()
|
||||
username.hide()
|
||||
enet_host_toggled_on.emit(username.text)
|
||||
tab_container.tabs_visible = false
|
||||
return
|
||||
|
||||
tab_container.tabs_visible = true
|
||||
enet_host_toggled_off.emit()
|
||||
enet_address_entry.show()
|
||||
enet_join_button.show()
|
||||
username.show()
|
||||
|
||||
func _on_enet_join_pressed() -> void:
|
||||
if enet_address_entry.text.is_empty() == false:
|
||||
Global.enet_address = enet_address_entry.text
|
||||
|
||||
tab_container.tabs_visible = false
|
||||
enet_join_pressed.emit(username.text)
|
||||
enet_join_button.hide()
|
||||
tab_container.hide()
|
||||
username.hide()
|
||||
disconnect_button.show()
|
||||
|
||||
func _on_steam_lobby_id_button_pressed():
|
||||
DisplayServer.clipboard_set(steam_lobby_id)
|
||||
|
||||
#endregion
|
||||
1
Scripts/Menu/lobby_menu.gd.uid
Normal file
1
Scripts/Menu/lobby_menu.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://b2pee67ics25u
|
||||
15
Scripts/Resources/inventory.gd
Normal file
15
Scripts/Resources/inventory.gd
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
extends Resource
|
||||
|
||||
class_name Inventory
|
||||
|
||||
var items : Array[RigidBody3D]
|
||||
|
||||
|
||||
func get_current_slot(index : int) -> RigidBody3D:
|
||||
return items[index]
|
||||
|
||||
func add_item(item : RigidBody3D) -> void:
|
||||
items.append(item)
|
||||
|
||||
func remove_items(item : RigidBody3D) -> void:
|
||||
items.erase(item)
|
||||
1
Scripts/Resources/inventory.gd.uid
Normal file
1
Scripts/Resources/inventory.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://darcj1vokaiv2
|
||||
9
Scripts/Resources/item.gd
Normal file
9
Scripts/Resources/item.gd
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
extends Resource
|
||||
|
||||
class_name Item
|
||||
|
||||
@export var value : int
|
||||
@export var name : String
|
||||
@export var weight : int
|
||||
@export var primary_objective : bool
|
||||
@export var secondary_objective : bool
|
||||
1
Scripts/Resources/item.gd.uid
Normal file
1
Scripts/Resources/item.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://ctwdmnqaxkty
|
||||
12
Scripts/Server/player_data.gd
Normal file
12
Scripts/Server/player_data.gd
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
class_name PlayerData
|
||||
|
||||
extends Resource
|
||||
|
||||
@export var id : int
|
||||
@export var lobby_index : int
|
||||
@export var name : String
|
||||
|
||||
func _init(new_id : int = -1, new_lobby_index : int = -1, new_name : String = "username"):
|
||||
id = new_id
|
||||
lobby_index = new_lobby_index
|
||||
name = new_name
|
||||
1
Scripts/Server/player_data.gd.uid
Normal file
1
Scripts/Server/player_data.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://b8fojvchw16hl
|
||||
273
Scripts/Server/server.gd
Normal file
273
Scripts/Server/server.gd
Normal file
|
|
@ -0,0 +1,273 @@
|
|||
class_name Server
|
||||
|
||||
extends Node
|
||||
|
||||
|
||||
#region Constants
|
||||
|
||||
const DEFAULT_PORT = 10567
|
||||
const MAX_CLIENTS = 3
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Onready Variables
|
||||
|
||||
# @onready var microphone : AudioStreamPlayer3D = $Microphone
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Variables
|
||||
|
||||
var players_ready : Array = []
|
||||
|
||||
var peer : MultiplayerPeer = null
|
||||
|
||||
#var mic_capture : AudioEffectOpusChunked
|
||||
|
||||
var lobby_id : int = -1
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region RPC
|
||||
|
||||
# @rpc("any_peer", "unreliable")
|
||||
# func voice_packet_recieved(packet):
|
||||
# var sender_id = multiplayer.get_remote_sender_id()
|
||||
# push_opus_packet_to_player.emit(sender_id, packet)
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Signals
|
||||
|
||||
signal game_log(message : String, color : Color)
|
||||
|
||||
signal server_close()
|
||||
|
||||
signal client_connected_to_server()
|
||||
|
||||
signal client_disconnected_from_server()
|
||||
|
||||
signal remove_client_from_server(id : int)
|
||||
|
||||
signal steam_lobby_created()
|
||||
|
||||
# signal push_opus_packet_to_player(id : int, packet)
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Godot Functions
|
||||
|
||||
func _ready() -> void:
|
||||
for argument in OS.get_cmdline_args():
|
||||
if argument == "-steam":
|
||||
ready_steam()
|
||||
|
||||
# ready_voip()
|
||||
|
||||
#set multiplayer signals
|
||||
multiplayer.peer_connected.connect(_multiplayer_peer_connected)
|
||||
multiplayer.peer_disconnected.connect(_multiplayer_peer_disconnected)
|
||||
multiplayer.connected_to_server.connect(_multiplayer_connected_to_server)
|
||||
multiplayer.connection_failed.connect(_multiplayer_connection_failed)
|
||||
multiplayer.server_disconnected.connect(_multiplayer_server_disconnected)
|
||||
|
||||
|
||||
#set steam signals
|
||||
if Global.steam_connected == true:
|
||||
Steam.lobby_joined.connect(_steam_lobby_joined)
|
||||
Steam.lobby_created.connect(_steam_lobby_created)
|
||||
|
||||
func _process(_delta : float):
|
||||
# process_voip()
|
||||
Steam.run_callbacks()
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Ready Functions
|
||||
|
||||
func ready_steam() -> void:
|
||||
var steam_response : Dictionary = Steam.steamInitEx()
|
||||
Global.steam_connected = steam_response["status"] == 0
|
||||
|
||||
if Global.steam_connected == false:
|
||||
get_tree().create_timer(3.0).timeout.connect(
|
||||
func():
|
||||
game_log.emit("Could Not Connect To Steam", Color(1, 0, 0, 1))
|
||||
)
|
||||
|
||||
# func ready_voip() -> void:
|
||||
# assert(microphone.bus == "MicrophoneBus")
|
||||
# var mic_bus = AudioServer.get_bus_index("MicrophoneBus")
|
||||
# mic_capture = AudioServer.get_bus_effect(mic_bus, 0)
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Process Functions
|
||||
|
||||
# func process_voip() -> void:
|
||||
# if mic_capture == null:
|
||||
# return
|
||||
|
||||
# while mic_capture.chunk_available():
|
||||
# var packet = mic_capture.read_opus_packet(PackedByteArray())
|
||||
# mic_capture.drop_chunk()
|
||||
|
||||
# if Global.voip_on == false:
|
||||
# continue
|
||||
|
||||
# if Global.is_multiplayer and multiplayer.multiplayer_peer.get_connection_status() == MultiplayerPeer.CONNECTION_CONNECTED:
|
||||
# voice_packet_recieved.rpc(packet)
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Default Multiplayer Functions
|
||||
|
||||
func destroy_lobby() -> void:
|
||||
Global.is_multiplayer = false
|
||||
|
||||
multiplayer.multiplayer_peer.close()
|
||||
peer = OfflineMultiplayerPeer.new()
|
||||
multiplayer.multiplayer_peer = peer
|
||||
|
||||
server_close.emit()
|
||||
|
||||
func disconnect_client() -> void:
|
||||
Global.is_multiplayer = false
|
||||
|
||||
multiplayer.multiplayer_peer.close()
|
||||
peer = OfflineMultiplayerPeer.new()
|
||||
multiplayer.multiplayer_peer = peer
|
||||
|
||||
client_disconnected_from_server.emit()
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Enet Functions
|
||||
|
||||
func enet_create_host() -> void:
|
||||
#set multiplayer to true
|
||||
Global.is_multiplayer = true
|
||||
|
||||
#init multiplayer host
|
||||
peer = ENetMultiplayerPeer.new()
|
||||
(peer as ENetMultiplayerPeer).create_server(DEFAULT_PORT, MAX_CLIENTS)
|
||||
multiplayer.multiplayer_peer = peer
|
||||
|
||||
func enet_create_client(address : String) -> void:
|
||||
#set multiplayer to true
|
||||
Global.is_multiplayer = true
|
||||
|
||||
#init client and wait for connection
|
||||
peer = ENetMultiplayerPeer.new()
|
||||
(peer as ENetMultiplayerPeer).create_client(address, DEFAULT_PORT)
|
||||
multiplayer.set_multiplayer_peer(peer)
|
||||
await multiplayer.connected_to_server
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Steam Functions
|
||||
|
||||
func steam_create_host() -> void:
|
||||
#players[1] = PlayerData.new(1, 0, new_username)
|
||||
Steam.createLobby(Steam.LOBBY_TYPE_FRIENDS_ONLY, MAX_CLIENTS)
|
||||
|
||||
func steam_join_lobby(new_lobby_id : int) -> void:
|
||||
Steam.joinLobby(new_lobby_id)
|
||||
|
||||
func steam_create_socket():
|
||||
Global.is_multiplayer = true
|
||||
|
||||
peer = SteamMultiplayerPeer.new()
|
||||
peer.create_host(0)
|
||||
multiplayer.set_multiplayer_peer(peer)
|
||||
|
||||
func steam_connect_socket(steam_id : int) -> void:
|
||||
Global.is_multiplayer = true
|
||||
|
||||
peer = SteamMultiplayerPeer.new()
|
||||
peer.create_client(steam_id, 0)
|
||||
multiplayer.set_multiplayer_peer(peer)
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Signal Functions
|
||||
|
||||
func _multiplayer_peer_connected(_id : int):
|
||||
pass
|
||||
|
||||
func _multiplayer_peer_disconnected(id : int):
|
||||
if multiplayer.is_server():
|
||||
game_log.emit("Player \"" + str(id) + "\" disconnected", Color(1, 0, 0, 1))
|
||||
remove_client_from_server.emit(id)
|
||||
|
||||
func _multiplayer_connected_to_server() -> void:
|
||||
client_connected_to_server.emit()
|
||||
|
||||
func _multiplayer_connection_failed() -> void:
|
||||
Global.is_multiplayer = false
|
||||
peer = OfflineMultiplayerPeer.new()
|
||||
multiplayer.multiplayer_peer = peer
|
||||
client_disconnected_from_server.emit()
|
||||
game_log.emit("Server connection failed", Color(1, 0, 0, 1))
|
||||
|
||||
func _multiplayer_server_disconnected() -> void:
|
||||
Global.is_multiplayer = false
|
||||
peer = OfflineMultiplayerPeer.new()
|
||||
multiplayer.multiplayer_peer = peer
|
||||
client_disconnected_from_server.emit()
|
||||
game_log.emit("Server disconnected", Color(1, 0, 0, 1))
|
||||
|
||||
func _steam_lobby_joined(new_lobby_id : int, _permissions : int, _locked : bool, response : int) -> void:
|
||||
if response == Steam.CHAT_ROOM_ENTER_RESPONSE_SUCCESS:
|
||||
lobby_id = new_lobby_id
|
||||
var id : int = Steam.getLobbyOwner(new_lobby_id)
|
||||
if id != Steam.getSteamID():
|
||||
steam_connect_socket(id)
|
||||
#player_register.rpc(username)
|
||||
#players[multiplayer.get_unique_id()] = username
|
||||
return
|
||||
var message : String
|
||||
match response:
|
||||
Steam.CHAT_ROOM_ENTER_RESPONSE_DOESNT_EXIST:
|
||||
message = "This lobby no longer exists."
|
||||
Steam.CHAT_ROOM_ENTER_RESPONSE_NOT_ALLOWED:
|
||||
message = "You don't have permission to join this lobby."
|
||||
Steam.CHAT_ROOM_ENTER_RESPONSE_FULL:
|
||||
message = "The lobby is now full."
|
||||
Steam.CHAT_ROOM_ENTER_RESPONSE_ERROR:
|
||||
message = "Response errored."
|
||||
Steam.CHAT_ROOM_ENTER_RESPONSE_BANNED:
|
||||
message = "You are banned from this lobby."
|
||||
Steam.CHAT_ROOM_ENTER_RESPONSE_LIMITED:
|
||||
message = "You cannot join due to having a limited account."
|
||||
Steam.CHAT_ROOM_ENTER_RESPONSE_CLAN_DISABLED:
|
||||
message = "This lobby is locked or disabled."
|
||||
Steam.CHAT_ROOM_ENTER_RESPONSE_COMMUNITY_BAN:
|
||||
message = "This lobby is community locked."
|
||||
Steam.CHAT_ROOM_ENTER_RESPONSE_MEMBER_BLOCKED_YOU:
|
||||
message = "A user in the lobby has blocked you from joining."
|
||||
Steam.CHAT_ROOM_ENTER_RESPONSE_YOU_BLOCKED_MEMBER:
|
||||
message = "A user you have blocked is in the lobby."
|
||||
game_log.emit(message, Color(1, 0, 0, 1))
|
||||
|
||||
func _steam_lobby_created(connected: int, this_lobby_id: int) -> void:
|
||||
if connected == 1:
|
||||
Global.steam_lobby_id = str(this_lobby_id)
|
||||
Steam.setLobbyData(this_lobby_id, "name", str(Steam.getPersonaName(), "'s test server"))
|
||||
steam_create_socket()
|
||||
steam_lobby_created.emit()
|
||||
return
|
||||
game_log.emit("Error on create lobby!", Color(1, 0, 0, 1))
|
||||
|
||||
#endregion
|
||||
1
Scripts/Server/server.gd.uid
Normal file
1
Scripts/Server/server.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://dwwtrox3lp2jp
|
||||
71
Scripts/Server/server_lobby.gd
Normal file
71
Scripts/Server/server_lobby.gd
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
class_name ServerLobby
|
||||
extends Node
|
||||
|
||||
|
||||
#region Exports
|
||||
|
||||
@export var players : Dictionary[int, PlayerData] = {}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Variables
|
||||
|
||||
var free_lobby_indexs : Array[int] = []
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Signals
|
||||
|
||||
signal player_registered()
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Client RPC
|
||||
|
||||
@rpc("any_peer", "call_local")
|
||||
func request_player_register(id: int, username) -> void:
|
||||
#only run on the multiplayer instance
|
||||
if not multiplayer.is_server():
|
||||
return
|
||||
|
||||
player_register.rpc_id(1, id, username)
|
||||
|
||||
@rpc("any_peer", "call_local")
|
||||
func update_client_players(id : int, username : String) -> void:
|
||||
if not players.has(id):
|
||||
players[id] = PlayerData.new(id, players.size(), username)
|
||||
|
||||
player_registered.emit()
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Server RPC
|
||||
|
||||
@rpc("authority", "call_local")
|
||||
func player_register(id : int, username : String) -> void:
|
||||
var lobby_index : int = players.size()
|
||||
if free_lobby_indexs.size() != 0:
|
||||
lobby_index = free_lobby_indexs.pop_front()
|
||||
|
||||
players[id] = PlayerData.new(id, lobby_index, username)
|
||||
|
||||
#send the entire list for clients that join later
|
||||
for player_id in players:
|
||||
update_client_players.rpc(player_id, players[player_id].name)
|
||||
|
||||
@rpc("authority", "call_local")
|
||||
func player_unregister(id) -> void:
|
||||
free_lobby_indexs.append(players[id].lobby_index)
|
||||
players.erase(id)
|
||||
player_registered.emit()
|
||||
|
||||
@rpc("authority", "call_local")
|
||||
func players_clear() -> void:
|
||||
players.clear()
|
||||
player_registered.emit()
|
||||
|
||||
#endregion
|
||||
1
Scripts/Server/server_lobby.gd.uid
Normal file
1
Scripts/Server/server_lobby.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://k0xvfdmvtyrt
|
||||
49
Scripts/fpc/EditorModule.gd
Normal file
49
Scripts/fpc/EditorModule.gd
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
@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
|
||||
1
Scripts/fpc/EditorModule.gd.uid
Normal file
1
Scripts/fpc/EditorModule.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://c5g0jt1apb2al
|
||||
551
Scripts/fpc/character.gd
Normal file
551
Scripts/fpc/character.gd
Normal file
|
|
@ -0,0 +1,551 @@
|
|||
# COPYRIGHT Colormatic Studios
|
||||
# MIT license
|
||||
# Quality Godot First Person Controller v2
|
||||
|
||||
class_name Player
|
||||
extends CharacterBody3D
|
||||
|
||||
|
||||
#region Character Export Group
|
||||
|
||||
## 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 X axis input for the camera.
|
||||
@export var invert_camera_x_axis : bool = false
|
||||
## Invert the Y axis input for the camera.
|
||||
@export var invert_camera_y_axis : bool = false
|
||||
## Whether 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 = "res://Scenes/reticles/reticle_1.tscn"
|
||||
|
||||
#endregion
|
||||
|
||||
#region Nodes Export Group
|
||||
|
||||
@export_group("Nodes")
|
||||
## A reference to the camera for use in the character script. This is the parent node to the camera and is rotated instead of the camera for mouse input.
|
||||
@export var HEAD : Node3D
|
||||
## A reference to the camera for use in the character script.
|
||||
@export var CAMERA : Camera3D
|
||||
# A reference to the Camera Ray Cast
|
||||
@export var CAMERA_RAYCAST : RayCast3D
|
||||
# current item player is looking at
|
||||
@onready var HIGHLIGHTED_ITEM : RigidBody3D
|
||||
# A reference to the inventory
|
||||
@export var INVENTORY : Inventory
|
||||
# A reference to the inventory menu
|
||||
@onready var inventory_menu : InventoryMenu
|
||||
## A reference to the headbob animation for use in the character script.
|
||||
@export var HEADBOB_ANIMATION : AnimationPlayer
|
||||
## A reference to the jump animation for use in the character script.
|
||||
@export var JUMP_ANIMATION : AnimationPlayer
|
||||
## A reference to the crouch animation for use in the character script.
|
||||
@export var CROUCH_ANIMATION : AnimationPlayer
|
||||
## A reference to the the player's collision shape for use in the character script.
|
||||
@export var COLLISION_MESH : CollisionShape3D
|
||||
|
||||
#endregion
|
||||
|
||||
#region Controls Export Group
|
||||
|
||||
# We are using UI controls because they are built into Godot Engine so they can be used right away
|
||||
@export_group("Controls")
|
||||
## Use the Input Map to map a mouse/keyboard input to an action and add a reference to it to this dictionary to be used in the script.
|
||||
@export var controls : Dictionary = {
|
||||
LEFT = "move_left",
|
||||
RIGHT = "move_right",
|
||||
FORWARD = "move_forward",
|
||||
BACKWARD = "move_back",
|
||||
JUMP = "jump",
|
||||
CROUCH = "crouch",
|
||||
SPRINT = "sprint",
|
||||
PAUSE = "pause",
|
||||
INTERACT = "interact",
|
||||
INVENTORY = "inventory"
|
||||
}
|
||||
@export_subgroup("Controller Specific")
|
||||
## This only affects how the camera is handled, the rest should be covered by adding controller inputs to the existing actions in the Input Map.
|
||||
@export var controller_support : bool = false
|
||||
## Use the Input Map to map a controller input to an action and add a reference to it to this dictionary to be used in the script.
|
||||
@export var controller_controls : Dictionary = {
|
||||
LOOK_LEFT = "look_left",
|
||||
LOOK_RIGHT = "look_right",
|
||||
LOOK_UP = "look_up",
|
||||
LOOK_DOWN = "look_down"
|
||||
}
|
||||
## The sensitivity of the analog stick that controls camera rotation. Lower is less sensitive and higher is more sensitive.
|
||||
@export_range(0.001, 1, 0.001) var look_sensitivity : float = 0.035
|
||||
|
||||
#endregion
|
||||
|
||||
#region Feature Settings Export Group
|
||||
|
||||
@export_group("Feature Settings")
|
||||
## Enable or disable jumping. Useful for restrictive storytelling environments.
|
||||
@export var jumping_enabled : bool = true
|
||||
## Whether 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
|
||||
## Enables or disables sprinting.
|
||||
@export var sprint_enabled : bool = true
|
||||
## Toggles the sprinting state when button is pressed or requires the player to hold the button down to remain sprinting.
|
||||
@export_enum("Hold to Sprint", "Toggle Sprint") var sprint_mode : int = 0
|
||||
## Enables or disables crouching.
|
||||
@export var crouch_enabled : bool = true
|
||||
## Toggles the crouch state when button is pressed or requires the player to hold the button down to remain crouched.
|
||||
@export_enum("Hold to Crouch", "Toggle Crouch") var crouch_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
|
||||
## If your game changes the gravity value during gameplay, check this property to allow the player to experience the change in gravity.
|
||||
@export var dynamic_gravity : bool = false
|
||||
|
||||
#endregion
|
||||
|
||||
#region Member Variable Initialization
|
||||
|
||||
# These are variables used in this script that don't need to be exposed in the editor.
|
||||
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 ceiling 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 physics process
|
||||
var mouseInput : Vector2 = Vector2(0,0)
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Godot Functions
|
||||
func _enter_tree() -> void:
|
||||
|
||||
#get the id off the player name and set authority
|
||||
var new_id = name.lstrip("Player")
|
||||
set_multiplayer_authority(new_id.to_int())
|
||||
|
||||
func _ready():
|
||||
#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)
|
||||
|
||||
initialize_animations()
|
||||
check_controls()
|
||||
enter_normal_state()
|
||||
if is_multiplayer_authority():
|
||||
CAMERA.current = true
|
||||
inventory_menu = $UserInterface/InventoryMenu
|
||||
inventory_menu.inventory = INVENTORY
|
||||
|
||||
func _process(_delta):
|
||||
# if pausing_enabled:
|
||||
# handle_pausing()
|
||||
|
||||
update_debug_menu_per_frame()
|
||||
|
||||
handle_open_inventory()
|
||||
|
||||
|
||||
func _physics_process(delta): # Most things happen here.
|
||||
# Gravity
|
||||
if dynamic_gravity:
|
||||
gravity = ProjectSettings.get_setting("physics/3d/default_gravity")
|
||||
if not is_on_floor() and gravity and gravity_enabled:
|
||||
velocity.y -= gravity * delta
|
||||
handle_jumping()
|
||||
|
||||
var input_dir = Vector2.ZERO
|
||||
|
||||
if not immobile && !Global.in_menu: # Immobility works by interrupting user input, so other forces can still be applied to the player
|
||||
input_dir = Input.get_vector(controls.LEFT, controls.RIGHT, controls.FORWARD, controls.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:
|
||||
play_headbob_animation(input_dir)
|
||||
|
||||
if jump_animation:
|
||||
play_jump_animation()
|
||||
handle_interact()
|
||||
update_debug_menu_per_tick()
|
||||
|
||||
was_on_floor = is_on_floor() # This must always be at the end of physics_process
|
||||
|
||||
#endregion
|
||||
|
||||
#region Server Functions
|
||||
|
||||
@rpc("any_peer", "call_local")
|
||||
func teleport_player(location: Vector3, new_rotation: Vector3) -> void:
|
||||
if not is_multiplayer_authority():
|
||||
return
|
||||
global_position = location
|
||||
HEAD.rotation = new_rotation
|
||||
velocity = Vector3.ZERO
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region Input Handling
|
||||
|
||||
func handle_jumping():
|
||||
if jumping_enabled:
|
||||
if continuous_jumping: # Hold down the jump button
|
||||
if Input.is_action_pressed(controls.JUMP) and is_on_floor() and !low_ceiling and !Global.in_menu:
|
||||
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(controls.JUMP) and is_on_floor() and !low_ceiling and !Global.in_menu:
|
||||
if jump_animation:
|
||||
JUMP_ANIMATION.play("jump", 0.25)
|
||||
velocity.y += jump_velocity
|
||||
|
||||
|
||||
func handle_movement(delta, input_dir):
|
||||
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 invert_camera_x_axis:
|
||||
HEAD.rotation_degrees.y -= mouseInput.x * mouse_sensitivity * -1
|
||||
else:
|
||||
HEAD.rotation_degrees.y -= mouseInput.x * mouse_sensitivity
|
||||
|
||||
if invert_camera_y_axis:
|
||||
HEAD.rotation_degrees.x -= mouseInput.y * mouse_sensitivity * -1
|
||||
else:
|
||||
HEAD.rotation_degrees.x -= mouseInput.y * mouse_sensitivity
|
||||
|
||||
if controller_support:
|
||||
var controller_view_rotation = Input.get_vector(controller_controls.LOOK_DOWN, controller_controls.LOOK_UP, controller_controls.LOOK_RIGHT, controller_controls.LOOK_LEFT) * look_sensitivity # These are inverted because of the nature of 3D rotation.
|
||||
if invert_camera_x_axis:
|
||||
HEAD.rotation.x += controller_view_rotation.x * -1
|
||||
else:
|
||||
HEAD.rotation.x += controller_view_rotation.x
|
||||
|
||||
if invert_camera_y_axis:
|
||||
HEAD.rotation.y += controller_view_rotation.y * -1
|
||||
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_interact():
|
||||
if CAMERA_RAYCAST.is_colliding():
|
||||
var interactable = CAMERA_RAYCAST.get_collider()
|
||||
if "interactable" in interactable:
|
||||
HIGHLIGHTED_ITEM = interactable
|
||||
interactable.interactable.outline.show()
|
||||
if "item" in interactable:
|
||||
if Input.is_action_just_pressed(controls.INTERACT):
|
||||
print(CAMERA_RAYCAST.get_collider())
|
||||
var item = interactable as RigidBody3D
|
||||
item.freeze = true
|
||||
item.collision_layer = 0
|
||||
item.hide()
|
||||
INVENTORY.add_item(item)
|
||||
print("This is a item")
|
||||
elif HIGHLIGHTED_ITEM != null:
|
||||
HIGHLIGHTED_ITEM.get_node("Interactable").outline.hide()
|
||||
HIGHLIGHTED_ITEM = null
|
||||
|
||||
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 !InputMap.has_action(controls.JUMP):
|
||||
push_error("No control mapped for jumping. Please add an input map control. Disabling jump.")
|
||||
jumping_enabled = false
|
||||
if !InputMap.has_action(controls.LEFT):
|
||||
push_error("No control mapped for move left. Please add an input map control. Disabling movement.")
|
||||
immobile = true
|
||||
if !InputMap.has_action(controls.RIGHT):
|
||||
push_error("No control mapped for move right. Please add an input map control. Disabling movement.")
|
||||
immobile = true
|
||||
if !InputMap.has_action(controls.FORWARD):
|
||||
push_error("No control mapped for move forward. Please add an input map control. Disabling movement.")
|
||||
immobile = true
|
||||
if !InputMap.has_action(controls.BACKWARD):
|
||||
push_error("No control mapped for move backward. Please add an input map control. Disabling movement.")
|
||||
immobile = true
|
||||
if !InputMap.has_action(controls.PAUSE):
|
||||
push_error("No control mapped for pause. Please add an input map control. Disabling pausing.")
|
||||
pausing_enabled = false
|
||||
if !InputMap.has_action(controls.CROUCH):
|
||||
push_error("No control mapped for crouch. Please add an input map control. Disabling crouching.")
|
||||
crouch_enabled = false
|
||||
if !InputMap.has_action(controls.SPRINT):
|
||||
push_error("No control mapped for sprint. Please add an input map control. Disabling sprinting.")
|
||||
sprint_enabled = false
|
||||
|
||||
func handle_open_inventory(force_toggle : bool = false):
|
||||
if Input.is_action_just_pressed(controls.INVENTORY) || force_toggle:
|
||||
Global.inventory_showing = inventory_menu.toggle_inventory()
|
||||
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
|
||||
#endregion
|
||||
|
||||
#region State Handling
|
||||
|
||||
func handle_state(moving):
|
||||
if sprint_enabled:
|
||||
if sprint_mode == 0:
|
||||
if Input.is_action_pressed(controls.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 scenario
|
||||
if Input.is_action_pressed(controls.SPRINT) and state == "normal":
|
||||
enter_sprint_state()
|
||||
if Input.is_action_just_pressed(controls.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(controls.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(controls.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():
|
||||
#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():
|
||||
#print("entering crouch state")
|
||||
state = "crouching"
|
||||
speed = crouch_speed
|
||||
CROUCH_ANIMATION.play("crouch")
|
||||
|
||||
func enter_sprint_state():
|
||||
#print("entering sprint state")
|
||||
var prev_state = state
|
||||
if prev_state == "crouching":
|
||||
CROUCH_ANIMATION.play_backwards("crouch")
|
||||
state = "sprinting"
|
||||
speed = sprint_speed
|
||||
|
||||
#endregion
|
||||
|
||||
#region Animation Handling
|
||||
|
||||
func initialize_animations():
|
||||
# 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")
|
||||
|
||||
func play_headbob_animation(moving):
|
||||
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 play_jump_animation():
|
||||
if !was_on_floor and is_on_floor(): # The player just landed
|
||||
var facing_direction : Vector3 = CAMERA.get_global_transform().basis.x
|
||||
var facing_direction_2D : Vector2 = Vector2(facing_direction.x, facing_direction.z).normalized()
|
||||
var velocity_2D : Vector2 = Vector2(velocity.x, velocity.z).normalized()
|
||||
|
||||
# Compares velocity direction against the camera direction (via dot product) to determine which landing animation to play.
|
||||
var side_landed : int = round(velocity_2D.dot(facing_direction_2D))
|
||||
|
||||
if side_landed > 0:
|
||||
JUMP_ANIMATION.play("land_right", 0.25)
|
||||
elif side_landed < 0:
|
||||
JUMP_ANIMATION.play("land_left", 0.25)
|
||||
else:
|
||||
JUMP_ANIMATION.play("land_center", 0.25)
|
||||
|
||||
#endregion
|
||||
|
||||
#region Debug Menu
|
||||
|
||||
func update_debug_menu_per_frame():
|
||||
$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)
|
||||
|
||||
|
||||
func update_debug_menu_per_tick():
|
||||
# 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)
|
||||
|
||||
|
||||
func _unhandled_input(event : InputEvent):
|
||||
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
|
||||
|
||||
#endregion
|
||||
|
||||
#region Misc Functions
|
||||
|
||||
func change_reticle(reticle): # Yup, this function is kinda strange
|
||||
if not is_multiplayer_authority():
|
||||
return
|
||||
if RETICLE:
|
||||
RETICLE.queue_free()
|
||||
|
||||
RETICLE = load(reticle).instantiate()
|
||||
RETICLE.character = self
|
||||
$UserInterface.add_child(RETICLE)
|
||||
|
||||
|
||||
func update_camera_fov():
|
||||
if state == "sprinting":
|
||||
CAMERA.fov = lerp(CAMERA.fov, 85.0, 0.3)
|
||||
else:
|
||||
CAMERA.fov = lerp(CAMERA.fov, 75.0, 0.3)
|
||||
|
||||
func handle_pausing():
|
||||
if Global.inventory_showing:
|
||||
handle_open_inventory()
|
||||
if Input.is_action_just_pressed(controls.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
|
||||
|
||||
#endregion
|
||||
1
Scripts/fpc/character.gd.uid
Normal file
1
Scripts/fpc/character.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://c1um4tmthbbpk
|
||||
18
Scripts/fpc/debug.gd
Normal file
18
Scripts/fpc/debug.gd
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
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)
|
||||
1
Scripts/fpc/debug.gd.uid
Normal file
1
Scripts/fpc/debug.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://bhfftu01dsfk7
|
||||
29
Scripts/global.gd
Normal file
29
Scripts/global.gd
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
extends Node
|
||||
|
||||
#region Constants
|
||||
|
||||
const DEFAULT_ENET_ADDRESS = "127.0.0.1"
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Variables
|
||||
|
||||
var is_admin : bool = true
|
||||
|
||||
var is_multiplayer : bool = false
|
||||
|
||||
var steam_connected : bool = false
|
||||
|
||||
var in_game : bool = false
|
||||
var in_menu : bool = false
|
||||
var inventory_showing : bool = false
|
||||
|
||||
var enet_address : String = DEFAULT_ENET_ADDRESS
|
||||
var steam_lobby_id : String = ""
|
||||
|
||||
var controller_connected : bool = false
|
||||
|
||||
var voip_on : bool = false
|
||||
|
||||
#endregion
|
||||
1
Scripts/global.gd.uid
Normal file
1
Scripts/global.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://bma0n1wnb0yxd
|
||||
86
Scripts/world.gd
Normal file
86
Scripts/world.gd
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
extends Node
|
||||
|
||||
@export var lobby_menu : LobbyMenu
|
||||
var menu_showing : bool = false;
|
||||
|
||||
@export var server : Server
|
||||
|
||||
@export var level: Level
|
||||
|
||||
@onready var chat : ChatMenu = $ChatMenu
|
||||
|
||||
func _ready() -> void:
|
||||
lobby_menu.enet_host_toggled_on.connect(_enet_host_on)
|
||||
lobby_menu.enet_join_pressed.connect(_enet_join_pressed)
|
||||
lobby_menu.disconnect_button_pressed.connect(_disconnect_button_pressed)
|
||||
lobby_menu.enet_host_toggled_off.connect(_menu_toggle_host_off)
|
||||
server.client_connected_to_server.connect(_client_joined_server)
|
||||
server.remove_client_from_server.connect(_remove_client_from_server)
|
||||
server.client_disconnected_from_server.connect(_disconnect_from_server)
|
||||
server.server_close.connect(_server_close)
|
||||
server.game_log.connect(_server_send_chat_message)
|
||||
|
||||
func _physics_process(_delta: float) -> void:
|
||||
pause_toggle()
|
||||
|
||||
|
||||
func pause_toggle():
|
||||
if Input.is_action_just_pressed("pause"):
|
||||
if Global.inventory_showing:
|
||||
var player_id : int = multiplayer.get_unique_id()
|
||||
var player : Player = level.get_node("Player"+str(player_id))
|
||||
player.handle_open_inventory(true)
|
||||
return
|
||||
if !menu_showing:
|
||||
lobby_menu.show()
|
||||
menu_showing = true
|
||||
Global.in_menu = true
|
||||
Input.mouse_mode = Input.MOUSE_MODE_VISIBLE
|
||||
|
||||
elif menu_showing:
|
||||
lobby_menu.hide()
|
||||
menu_showing = false
|
||||
Global.in_menu = false
|
||||
Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
|
||||
|
||||
func _enet_host_on(username: String) -> void:
|
||||
print("Server started, Host: " + username);
|
||||
server.enet_create_host()
|
||||
|
||||
|
||||
func _enet_join_pressed(_username: String) -> void:
|
||||
print("... Joining " + Global.enet_address)
|
||||
var playername : Player = level.get_node("Player1")
|
||||
level.remove_child(playername)
|
||||
server.enet_create_client(Global.enet_address)
|
||||
|
||||
|
||||
func _client_joined_server() -> void:
|
||||
|
||||
var player_id : int = multiplayer.get_unique_id()
|
||||
level.request_spawn_player.rpc(player_id)
|
||||
lobby_menu.hide()
|
||||
menu_showing = false
|
||||
Global.in_menu = false
|
||||
|
||||
func _menu_toggle_host_off() -> void:
|
||||
server.destroy_lobby()
|
||||
lobby_menu.reset_visible()
|
||||
|
||||
func _server_close() -> void:
|
||||
level.remove_players(false)
|
||||
lobby_menu.reset_visible()
|
||||
|
||||
func _disconnect_button_pressed():
|
||||
server.disconnect_client()
|
||||
lobby_menu.reset_visible()
|
||||
|
||||
func _remove_client_from_server(id : int) -> void:
|
||||
level.remove_client_from_server.rpc_id(1, id)
|
||||
|
||||
func _disconnect_from_server():
|
||||
level.disconnect_from_server()
|
||||
|
||||
|
||||
func _server_send_chat_message(message : String, color : Color) -> void:
|
||||
chat.send_message(message, false, color)
|
||||
1
Scripts/world.gd.uid
Normal file
1
Scripts/world.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://klp20wju1i26
|
||||
Loading…
Add table
Add a link
Reference in a new issue