From df861143a4308378f9ecdd1fff500158454bce73 Mon Sep 17 00:00:00 2001 From: unfa Date: Sun, 22 Aug 2021 23:33:33 +0200 Subject: [PATCH] Finished basic server-side player list implementation. --- Game/Assets/HUD/Chat.gd | 4 +- Game/Main.gd | 159 ++++++++++++++++++++++++---------------- 2 files changed, 96 insertions(+), 67 deletions(-) diff --git a/Game/Assets/HUD/Chat.gd b/Game/Assets/HUD/Chat.gd index 0eb540a..65e8105 100644 --- a/Game/Assets/HUD/Chat.gd +++ b/Game/Assets/HUD/Chat.gd @@ -52,8 +52,8 @@ func _unhandled_input(_event) -> void: get_tree().get_root().set_input_as_handled() # doesn't work over network due to missing RPC implementation in Godot 4 -@remotesync func chat_message(sender_id: int, recipient_team, message: String) -> void: - var sender_info = main.player_list[sender_id] +@remotesync func chat_message(sender_pid: int, recipient_team, message: String) -> void: + var sender_info = main.player_list.get(sender_pid) chat_history.append_bbcode('\n' + '[b][color=' + sender_info.color.to_html() +']' + str(sender_info.name) + '[/color][/b] : [i]' + message + '[/i]') func _on_Editor_text_submitted(new_text): diff --git a/Game/Main.gd b/Game/Main.gd index 431b5be..ed16f59 100644 --- a/Game/Main.gd +++ b/Game/Main.gd @@ -25,19 +25,22 @@ class PlayerInfo: var team: int var color: Color var focus: GameFocus - - func _init():#name: String, team: int, color: Color): -# self.name = name -# self.team = team -# self.color = color -# self.focus = 0 - + var health: int + + func _init():#name: String, team: int, color: Color): var player_name = "" for i in range(0, 4): player_name += ['a','b','c', 'd', 'e', 'f'][randi() % 5] self.name = player_name self.color = Color(randf(),randf(),randf()) self.team = 0 + self.focus = 999 + self.health = 100 +# else: +# self.name = name +# self.team = team +# self.color = color +# self.focus = 0 func serialize(): return { @@ -45,52 +48,59 @@ class PlayerInfo: 'team': str(self.team), 'color': self.color.to_html(), 'focus': self.focus, + 'health': self.health } - func set(name: String, team: int, color: Color, focus: int): + func set(name: String, team: int, color: Color, focus: int, health: int): self.name = name self.team = team self.color = color self.focus = focus + self.health = health func deserialize(info): - #var info_parsed = info.parse_json(info) self.name = info['name'] self.team = info['team'].to_int() self.color = Color.html(info['color']) self.focus = info['focus'] - + self.health = info['health'] #func generate(): func _process(delta): $Label.text = "player_list: \n" - for i in player_list.keys(): - $Label.text += str(i) + str(player_list[i].serialize()) + "\n" + for i in player_list.players.keys(): + if player_list.players[i]: + $Label.text += str(i) + " = " + str(player_list.get(i).serialize()) + "\n" + else: + $Label.text += str(i) + " = ???" -var local_player_info: PlayerInfo - -#class PlayerList: -# var items = {} +class PlayerList: + var players = {} # # func store(pid, item): # items[pid] = item -# -# func erase(pid): -# items.erase(pid) -# -# func update(pid, item): -# if items[pid]: -# items[pid] = item -# -# func get(): -# return items + + func erase(pid): + players.erase(pid) + + func set(pid: int, info: PlayerInfo): +# if info is PlayerInfo: + players[pid] = info +# else: +# var new_info = PlayerInfo.deserialize(info) +# players[pid] = new_info + + func get(pid: int) -> PlayerInfo: + return players[pid] -var player_list = {}: - set(player_list): - if role in [NetworkRole.SERVER, NetworkRole.DEDICATED_SERVER]: - for i in player_list: - rpc(&'player_list_update', i.serialize()) - else: - rpc_id(1, &'player_list_update', player_list.serialize()) +# func update(): +# if get_tree().network_peer.get_unique_id() == 1: +# for i in players.keys: +# rpc(&'player_list_update', i, players[i].serialize()) +# else: +# rpc_id(1, &'player_list_update', players[get_tree().network_peer.get_unique_id()].serialize()) + + +@onready var player_list = PlayerList.new() var focus = GameFocus.MENU : set(new_focus): @@ -135,48 +145,65 @@ func _input(_event) -> void: #@remote func update_player_list(player_list): # self.player_list = player_list -@remotesync func player_list_update(info): - var new_info = PlayerInfo.deserialize(info) - var id = get_tree().get_rpc_sender_id() - print("Updating player_list wit hnew info: ", new_info) - player_list[id] = new_info - print("Player list: ", player_list) - print("Player list item for id ", id, ": ", player_list[id]) +@remote func player_list_update(info, pid = get_tree().get_rpc_sender_id()): + if get_tree().network_peer.get_unique_id() == 1: # if we're server, we should store this + pid = get_tree().get_rpc_sender_id() #disallow clients setting player_info for other players than themselves + var new_info = PlayerInfo.new() + new_info.deserialize(info) + player_list.set(pid, new_info) + rpc(&'player_list_update', info, pid) # broadcast the new entry to clients + else: #we are client, so we're getting data relayed from the server + var new_info = PlayerInfo.new() + new_info.deserialize(info) + player_list.set(pid, new_info) # server relays other PID's data -func create_player(id: int, is_local: bool) -> void: +# if not id: +# id = get_tree().get_rpc_sender_id() +# +# print_debug("player_list_update ", info) +# if info is PlayerInfo: +# player_list.set(id, info) +# else: +# var new_info = PlayerInfo.deserialize(info) +# player_list.set(id, new_info) +# print("Updating player_list wit hnew info: ", new_info) +# +# print("Player list: ", player_list) +# print("Player list item for id ", id, ": ", player_list[id]) + +func create_player(pid: int, is_local: bool) -> void: var new_player - new_player = player_scene.instantiate() var spawnpoint = $Map/SpawnPoints.get_children()[randi() % len($Map/SpawnPoints.get_children())] - new_player.name = str(id) + new_player.name = str(pid) new_player.global_transform = spawnpoint.global_transform - new_player.set_network_master(id) + new_player.set_network_master(pid) $Players.add_child(new_player) if is_local: local_player = new_player #$Players.get_node(str(id)) local_player.get_node("Head/Camera").current = true var new_info = PlayerInfo.new() - #new_info.generate() - local_player_info = new_info - rpc_id(id, &'player_list_update', local_player_info.serialize()) # send player_info to others - player_list[id] = local_player_info + player_list.set(pid, new_info) - $NetworkTesting/TextEdit.text = local_player_info.name - $NetworkTesting/ColorPickerButton.color = local_player_info.color + if get_tree().network_peer.get_unique_id() != 1: #if we're not the server + rpc_id(1, &'player_list_update', new_info.serialize()) # send local player info to the server + + $NetworkTesting/TextEdit.text = new_info.name + $NetworkTesting/ColorPickerButton.color = new_info.color else: # make sure we use the right camera new_player.get_node("Head/Camera").current = false - if local_player: + if local_player: #if there is a local player, use it's camera local_player.get_node("Head/Camera").current = true -func start_dedicated_server(): +func start_dedicated_server(): # start server without creating a local player role = NetworkRole.DEDICATED_SERVER peer.create_server(NET_PORT, 16) get_tree().network_peer = peer #create_player(1, true) -func _on_Host_pressed(): +func _on_Host_pressed(): # start server and create a local player role = NetworkRole.SERVER $NetworkTesting/Host.disabled = true $NetworkTesting/Connect.disabled = true @@ -193,36 +220,38 @@ func _on_Connect_pressed(): peer.create_client(NET_SERVER, NET_PORT) get_tree().network_peer = peer -func _player_connected(id) -> void: - print("player connected, id: ", id) - create_player(id, false) +func _player_connected(pid) -> void: + print("player connected, id: ", pid) + create_player(pid, false) + + if get_tree().network_peer.get_unique_id() == 1: # if we're the server + for i in player_list.players.keys(): # send each player info entry to the newly connected client + rpc_id(pid, &'player_list_update', player_list.get(i).serialize(), i) # send local player info to the server + # if local_player: # local_player.rpc(&"update_info") # # if role in [NetworkRole.SERVER, NetworkRole.DEDICATED_SERVER]: # rpc_id(id, "player_list_update", player_list) -func _player_disconnected(id) -> void: - print("player disconnected, id: ", id) +func _player_disconnected(pid) -> void: + print("player disconnected, id: ", pid) func _connected_ok() -> void: print("connected to server") - var id = get_tree().get_network_unique_id() - create_player(id, true) + var pid = get_tree().get_network_unique_id() + create_player(pid, true) focus = GameFocus.GAME role = NetworkRole.CLIENT - # todo pull player list from server func _connected_fail() -> void: print("connection to server failed") func _server_disconnected() -> void: print("server disconnected") - role = NetworkRole.NONE func _ready() -> void: - print("Commandline arguments: ", OS.get_cmdline_args()) get_tree().connect("network_peer_connected", self._player_connected) @@ -233,7 +262,7 @@ func _ready() -> void: func _on_TextEdit_text_submitted(new_text): - local_player_info.name = new_text + player_list.players[get_tree().network_peer.get_unique_id()].name = new_text func _on_ColorPickerButton_color_changed(color): - local_player_info.color = color + player_list.players[get_tree().network_peer.get_unique_id()].color = color