243 lines
7.4 KiB
GDScript
243 lines
7.4 KiB
GDScript
extends Node
|
|
|
|
|
|
# Signals to let lobby GUI know what's going on.
|
|
signal player_list_changed()
|
|
signal connection_failed()
|
|
signal connection_succeeded()
|
|
signal game_ended()
|
|
signal game_started()
|
|
signal game_error(what)
|
|
|
|
# Default game server port. Can be any number between 1024 and 49151.
|
|
# Not on the list of registered or common ports as of November 2020:
|
|
# https://en.wikipedia.org/wiki/List_of_TCP_and_UDP_port_numbers
|
|
const DEFAULT_PORT = 10567
|
|
|
|
# Max number of players.
|
|
const MAX_PEERS = 4
|
|
|
|
var peer = null
|
|
|
|
# Name for my player.
|
|
var player_name = "The Warrior"
|
|
|
|
# Names for remote players in id:name format.
|
|
var players = {}
|
|
var players_ready = []
|
|
|
|
|
|
func _ready():
|
|
get_tree().connect("network_peer_connected", self, "_player_connected")
|
|
get_tree().connect("network_peer_disconnected", self,"_player_disconnected")
|
|
get_tree().connect("connected_to_server", self, "_connected_ok")
|
|
get_tree().connect("connection_failed", self, "_connected_fail")
|
|
get_tree().connect("server_disconnected", self, "_server_disconnected")
|
|
|
|
|
|
# Callback from SceneTree.
|
|
func _player_connected(id):
|
|
# Registration of a client beings here, tell the connected player that we are here.
|
|
rpc_id(id, "register_player", player_name)
|
|
|
|
|
|
# Callback from SceneTree.
|
|
func _player_disconnected(id):
|
|
##TODO: Need better way to determine a game is running
|
|
if has_node("/root/Main/ViewportContainer/Viewport/1"): # Game is in progress.
|
|
if get_tree().is_network_server():
|
|
emit_signal("game_error", "Player " + players[id] + " disconnected")
|
|
end_game()
|
|
else: # Game is not in progress.
|
|
# Unregister this player.
|
|
unregister_player(id)
|
|
|
|
|
|
# Callback from SceneTree, only for clients (not server).
|
|
func _connected_ok():
|
|
# We just connected to a server
|
|
emit_signal("connection_succeeded")
|
|
|
|
|
|
# Callback from SceneTree, only for clients (not server).
|
|
func _server_disconnected():
|
|
emit_signal("game_error", "Server disconnected")
|
|
end_game()
|
|
|
|
|
|
|
|
# Callback from SceneTree, only for clients (not server).
|
|
func _connected_fail():
|
|
get_tree().set_network_peer(null) # Remove peer
|
|
emit_signal("connection_failed")
|
|
|
|
# Lobby management functions.
|
|
|
|
remote func register_player(new_player_name):
|
|
var id = get_tree().get_rpc_sender_id()
|
|
print(id)
|
|
players[id] = new_player_name
|
|
emit_signal("player_list_changed")
|
|
|
|
|
|
func unregister_player(id):
|
|
players.erase(id)
|
|
emit_signal("player_list_changed")
|
|
|
|
func instance_on_peer_players(_scene :Resource, _node_path :NodePath, _global_position :Vector2 , _as_toplevel = true):
|
|
# print ("Scene Path: ", _scene.resource_path,
|
|
# " Instance At: ", _node_path,
|
|
# " Position : ", _global_position)
|
|
|
|
## was going to create local instance here but, lets see if I don't have to.
|
|
## makes me thing that node name and path must be very important for multiplayer
|
|
rpc("load_scene_on_all_clients", _scene.resource_path, _node_path, _global_position, _as_toplevel)
|
|
|
|
## remote means only runs on peers, remotesync goes both here and in peers
|
|
## because I want the node I load in two steps
|
|
remote func load_scene_on_all_clients(_scene :String, _node_path :NodePath, _global_position :Vector2 , _as_toplevel = true):
|
|
print ( "-- Remote Scene Call -- \n",
|
|
" Scene Path: ", _scene,
|
|
" Instance At: ", _node_path,
|
|
" Position : ", _global_position)
|
|
|
|
var new_scene = load(_scene).instance()
|
|
var _caller_id = get_tree().get_rpc_sender_id()
|
|
|
|
new_scene.set_network_master(_caller_id)
|
|
new_scene.set_as_toplevel(_as_toplevel)
|
|
new_scene.global_position = _global_position
|
|
|
|
get_node(_node_path).add_child(new_scene)
|
|
|
|
# for _player in players:
|
|
# rpc_id(_player, "load_scene_on_all_clients", _scene, _node_path, _global_position, _as_toplevel )
|
|
|
|
# if new_scene.get_network_master() == _caller_id:
|
|
# return new_scene
|
|
# else:
|
|
# return null
|
|
|
|
remote func pre_start_game(spawn_points):
|
|
# Change scene.
|
|
var _game_starting_level_scene = get_tree().get_root().get_node("/root/Main").starting_level
|
|
var _in_game_player_hud = get_tree().get_root().get_node("/root/Main").player_hud
|
|
#var world :Node = load("res://src/levels/TestBox.tscn").instance()
|
|
var world :Node = _game_starting_level_scene.instance()
|
|
#var ui :Node = load("res://src/ui/HUD.tscn").instance()
|
|
var ui :Node = _in_game_player_hud.instance()
|
|
|
|
## No need to name world anymore
|
|
#world.set_name("World")
|
|
world.add_to_group('world')
|
|
ui.add_to_group('world')
|
|
|
|
get_tree().get_root().get_node("/root/Main/ViewportContainer/Viewport").add_child(world)
|
|
get_tree().get_root().get_node("/root/Main/ViewportContainer/Viewport").add_child(ui)
|
|
|
|
get_tree().get_root().get_node("/root/Main/ViewportContainer/Viewport/Lobby").hide()
|
|
|
|
## Clear the PlayerInfo table in case this is a restart.
|
|
PlayerInfo.reset()
|
|
var player_scene = load("res://src/actors/players/playerE/PlayerE.tscn")
|
|
|
|
|
|
for p_id in spawn_points:
|
|
#var spawn_pos = world.get_node("SpawnPoints/" + str(spawn_points[p_id])).position
|
|
var player = player_scene.instance()
|
|
|
|
player.set_name(str(p_id)) # Use unique ID as node name.
|
|
#player.position=spawn_pos
|
|
player.set_network_master(p_id) #set unique id as master.
|
|
|
|
# We don't yet use a player name like a node yet
|
|
# if p_id == get_tree().get_network_unique_id():
|
|
# # If node for this peer id, set name.
|
|
# player.set_player_name(player_name)
|
|
# else:
|
|
# # Otherwise set name from peer.
|
|
# player.set_player_name(players[p_id])
|
|
|
|
get_tree().get_root().get_node("/root/Main/ViewportContainer/Viewport").add_child(player)
|
|
#world.get_node("Players").add_child(player)
|
|
|
|
# # Set up score.
|
|
# world.get_node("Score").add_player(get_tree().get_network_unique_id(), player_name)
|
|
# for pn in players:
|
|
# world.get_node("Score").add_player(pn, players[pn])
|
|
|
|
if not get_tree().is_network_server():
|
|
# Tell server we are ready to start.
|
|
rpc_id(1, "ready_to_start", get_tree().get_network_unique_id())
|
|
elif players.size() == 0:
|
|
post_start_game()
|
|
|
|
|
|
remote func post_start_game():
|
|
get_tree().set_pause(false) # Unpause and unleash the game!
|
|
emit_signal("game_started")
|
|
|
|
remote func ready_to_start(id):
|
|
assert(get_tree().is_network_server())
|
|
|
|
if not id in players_ready:
|
|
players_ready.append(id)
|
|
|
|
if players_ready.size() == players.size():
|
|
for p in players:
|
|
rpc_id(p, "post_start_game")
|
|
post_start_game()
|
|
|
|
|
|
func host_game(new_player_name):
|
|
player_name = new_player_name
|
|
peer = NetworkedMultiplayerENet.new()
|
|
peer.create_server(DEFAULT_PORT, MAX_PEERS)
|
|
get_tree().set_network_peer(peer)
|
|
|
|
|
|
func join_game(ip, new_player_name):
|
|
player_name = new_player_name
|
|
peer = NetworkedMultiplayerENet.new()
|
|
peer.create_client(ip, DEFAULT_PORT)
|
|
get_tree().set_network_peer(peer)
|
|
|
|
|
|
func get_player_list():
|
|
return players.values()
|
|
|
|
func get_player_ids():
|
|
return players.keys()
|
|
|
|
func get_player_name():
|
|
return player_name
|
|
|
|
|
|
func begin_game():
|
|
assert(get_tree().is_network_server())
|
|
|
|
# Create a dictionary with peer id and respective spawn points, could be improved by randomizing.
|
|
var spawn_points = {}
|
|
spawn_points[1] = 0 # Server in spawn point 0.
|
|
var spawn_point_idx = 1
|
|
for p in players:
|
|
spawn_points[p] = spawn_point_idx
|
|
spawn_point_idx += 1
|
|
# Call to pre-start game with the spawn points.
|
|
for p in players:
|
|
rpc_id(p, "pre_start_game", spawn_points)
|
|
|
|
pre_start_game(spawn_points)
|
|
|
|
func end_game():
|
|
rpc("end_clients_game")
|
|
|
|
remotesync func end_clients_game():
|
|
get_tree().call_group("world","queue_free")
|
|
# if has_node("/root/Main/ViewportContainer/Viewport/World"): # Game is in progress.
|
|
# # End it
|
|
# get_node("/root/Main/ViewportContainer/Viewport/World").queue_free()
|
|
|
|
emit_signal("game_ended")
|
|
players.clear()
|