diff options
Diffstat (limited to 'Game')
-rw-r--r-- | Game/Client.gd | 32 | ||||
-rw-r--r-- | Game/Network.gd | 154 | ||||
-rw-r--r-- | Game/Network.tscn | 13 | ||||
-rw-r--r-- | Game/Player.gd | 33 | ||||
-rw-r--r-- | Game/Player.tscn | 24 |
5 files changed, 107 insertions, 149 deletions
diff --git a/Game/Client.gd b/Game/Client.gd index dbaf69e..dc18765 100644 --- a/Game/Client.gd +++ b/Game/Client.gd @@ -9,17 +9,16 @@ var state: State : stage_state_changed.emit(value) var stage: Stage -var player: Player = Player.new() - -func _ready(): - #player = Player.new() - player.id = multiplayer.get_unique_id() +var _player: Player # workaround for MultiplayerSpawner +var player: Player: + get(): + if _player: return _player + else: return Network.get_player(multiplayer.get_unique_id()) -func update_player(): - Network.players[multiplayer.get_unique_id()] = player - Network.update_player.rpc(Network.to_rpc_object(player)) +func _ready(): + _player = preload("res://Game/Player.tscn").instantiate() func initialize_stage(current_stage: Stage): @@ -37,25 +36,20 @@ func place_tower(tower: Tower, position: Vector2): #Network.place_tower.rpc(Network.to_rpc_object(tower), position) player.towers[position] = tower - player.score += 1 - update_player() + #player.score += 1 func remove_tower(tower: Tower): if tower.owner_id == multiplayer.get_unique_id(): destroy_tower(tower) - player.score -= 1 - update_player() + #player.score -= 1 func destroy_tower(tower: Tower): - if multiplayer.is_server(): - stage.destroy_tower(tower) - else: - Network.destroy_tower.rpc_id(1, tower.global_position) + stage.destroy_tower(tower) + Network.destroy_tower.rpc(tower.global_position) player.towers.erase(tower.global_position) - update_player() func select_tower(tower: Tower): @@ -69,8 +63,8 @@ func deselect_tower(): tower.is_selected = false -func update_tower(tower: Tower, data: Dictionary): - Network.update_tower.rpc(tower.get_path(), data) +func update_tower(path: NodePath, data: Tower.NetworkData): + Network.update_tower.rpc(path, inst_to_dict(data)) func spawn_unit(unit: Unit, spawn: Spawn): diff --git a/Game/Network.gd b/Game/Network.gd index 48558ce..5f8be5c 100644 --- a/Game/Network.gd +++ b/Game/Network.gd @@ -19,140 +19,66 @@ func host_game(port): peer.create_server(int(port)) multiplayer.multiplayer_peer = peer - players[1] = Client.player + + Client.player.id = multiplayer.get_unique_id() + %Players.add_child(Client.player) func join_game(ip, port): var peer = ENetMultiplayerPeer.new() peer.create_client(ip, int(port)) multiplayer.multiplayer_peer = peer + + Client.player.id = multiplayer.get_unique_id() func _on_connected_to_server(): - print("connected to server") + print(multiplayer.get_unique_id(), ": connected to server") func _on_peer_connected(id): - print("peer connected: ", id) - add_to_players.rpc(to_rpc_object(Client.player)) + print(multiplayer.get_unique_id(), ": peer connected: ", id) + + if id == 1: # tell host to add player + add_to_players.rpc_id(1, inst_to_dict(Client.player)) + Client._player = null # TODO: add existing towers to new peers func _on_peer_disconnected(id): - print("peer disconnected: ", id) + print(multiplayer.get_unique_id(), ": peer disconnected: ", id) # TODO: move towers owned by peer to host - if id == 1: + if id == 1: # if host disconnected go back to Lobby get_tree().change_scene_to_file("res://UI/Lobby.tscn") -func get_ordered_player_ids(): - var keys = players.keys() - keys.sort_custom(func(a, b): +func get_player(id: int) -> Player: + return %Players.get_node(str(id)) + +func get_ordered_player_ids(): # TODO: return type needed for players_list.gd "find" method? + var keys = %Players.get_children().map(func(item: Player): + return item.id + ) + keys = keys.filter(func(item: int): # workaround for MultiplayerSpawner + Synchronizer + return item != 0 + ) + keys.sort_custom(func(a: int, b: int): return int(str(a).substr(0, 8)) < int(str(b).substr(0, 8)) ) return keys -func to_rpc_object(object: Variant): - var remote_object = {} - var properties = object.get_rpc_properties() - for property in properties: - var property_class = properties[property] - if object[property] is Dictionary: - remote_object[property] = {} - for key in object[property]: - remote_object[property][key] = to_rpc_object(object[property][key]) - elif property_class is String and property_class.begins_with("node://"): - remote_object[property] = object[property] - elif property_class: - remote_object[property] = to_rpc_object(object[property]) - else: - remote_object[property] = object[property] - - return remote_object - - -func from_rpc_object(remote_object: Dictionary, remote_class_path: String): - var object - var remote_class = load(remote_class_path) - if remote_class is PackedScene: - object = remote_class.instantiate() - elif remote_class is GDScript: - object = remote_class.new() - else: - assert(false, "unexpected remote class type") - - var properties = object.get_rpc_properties() - for property in properties: - var property_class = properties[property] - if object[property] is Dictionary: - for key in object[property]: - object[property][key] = from_rpc_object(remote_object[property], property_class) - elif property_class is String and property_class.begins_with("node://"): - var node_path = property_class.substr(7) # after node:// - object.remove_child(object.get_node(node_path)) - remote_object[property].name = node_path.get_basename() - object[property] = remote_object[property] - object.add_child(remote_object[property]) - elif property_class: - object[property] = from_rpc_object(remote_object[property], property_class) - else: - object[property] = remote_object[property] - - return object - - -func merge_with_rpc_object(object: Variant, remote_object: Dictionary): - var properties = object.get_rpc_properties() - for property in properties: - var property_class = properties[property] - if object[property] is Dictionary: - object[property] = {} - for key in remote_object[property]: - object[property][key] = from_rpc_object(remote_object[property][key], property_class) - elif property_class: - object[property] = merge_with_rpc_object(object[property], remote_object[property]) - else: - object[property] = remote_object[property] - - return object - - -@rpc("call_local", "any_peer") -func add_to_players(remote_player: Dictionary): - var id = multiplayer.get_remote_sender_id() - var player = from_rpc_object(remote_player, "res://Game/Player.gd") - player.id = id - players[id] = player - players_changed.emit() - - -@rpc("call_local", "any_peer") -func update_player(remote_player: Dictionary): +@rpc("any_peer") +func add_to_players(remote_data: Dictionary): var id = multiplayer.get_remote_sender_id() - var player = merge_with_rpc_object(players[id], remote_player) + + var player = preload("res://Game/Player.tscn").instantiate() player.id = id - players[id] = player - players_changed.emit() - - -@rpc("any_peer", "reliable") -func update_node(node_path: NodePath, properties: Dictionary): - var root_node = get_tree().root.get_node(node_path) + player.username = remote_data.username - for property in properties: - if property.contains(":"): - var child_node = get_nested_node_and_property(root_node, property) - child_node.node[child_node.property] = properties[property] - else: - root_node[property] = properties[property] - -func get_nested_node_and_property(node: Node, property: String) -> Dictionary: - if property.contains(":"): - var nested_node_path = property.substr(0, property.find(":")) - var nested_property = property.substr(property.find(":") + 1) - return get_nested_node_and_property(node.get_node(nested_node_path), nested_property) - return { "node": node, "property": property } + %Players.add_child(player) + + players_changed.emit() @rpc("any_peer") @@ -164,7 +90,7 @@ func place_tower(remote_data: Dictionary): var tower = Tower.from_network_data(data) tower.owner_id = remote_player_id - players[remote_player_id].towers[tower.global_position] = tower + Network.get_player(remote_player_id).towers[tower.global_position] = tower Client.stage.place_tower(tower, tower.global_position) @@ -173,23 +99,19 @@ func place_tower(remote_data: Dictionary): #func destroy_tower(remote_tower: Dictionary): func destroy_tower(position: Vector2): var owner_id = multiplayer.get_remote_sender_id() - var player = players[owner_id] as Player + var player = get_player(owner_id) var tower = player.towers.get(position) Client.stage.destroy_tower(tower) @rpc("any_peer") -func update_tower(remote_tower_node_path, data): +func update_tower(remote_tower_node_path: NodePath, remote_data: Dictionary): + var data: Tower.NetworkData = dict_to_inst(remote_data) var tower: Tower = get_tree().current_scene.get_node_or_null(remote_tower_node_path) + if tower: - if "components" in data: - for c in tower.components.duplicate(): - tower.remove_component(c.name) - for c in data.components: - tower.add_component( - load("res://Towers/Components/" + c + "Component.gd").new() - ) + tower.update_with_network_data(data) @rpc("any_peer") diff --git a/Game/Network.tscn b/Game/Network.tscn new file mode 100644 index 0000000..5e7c131 --- /dev/null +++ b/Game/Network.tscn @@ -0,0 +1,13 @@ +[gd_scene load_steps=2 format=3 uid="uid://dknyh6isiv5w4"] + +[ext_resource type="Script" path="res://Game/Network.gd" id="1_p1jvi"] + +[node name="Network" type="Node"] +script = ExtResource("1_p1jvi") + +[node name="Players" type="Node" parent="."] +unique_name_in_owner = true + +[node name="MultiplayerSpawner" type="MultiplayerSpawner" parent="."] +_spawnable_scenes = PackedStringArray("res://Game/Player.tscn") +spawn_path = NodePath("../Players") diff --git a/Game/Player.gd b/Game/Player.gd index dce19db..57eb73b 100644 --- a/Game/Player.gd +++ b/Game/Player.gd @@ -1,22 +1,25 @@ class_name Player -extends Resource +extends Node signal score_changed -var id := 1 -var name := "" +@export var username: String -var towers: Dictionary : - set(value): - towers = value - -var score: int : +@export var score: int : set(value): score = value score_changed.emit() +@export var id: int: + set(value): + id = value + name = str(value) + var units: Array[Unit] +var towers: Dictionary : + set(value): + towers = value func get_color(): @@ -30,9 +33,11 @@ func get_color(): return Color(rng.randf(), rng.randf(), rng.randf()) -func get_rpc_properties() -> Dictionary: - return { - "id": null, - "name": null, - "score": null, - } +func _on_multiplayer_synchronizer_synchronized() -> void: + Network.players_changed.emit() + +func _on_multiplayer_synchronizer_delta_synchronized() -> void: + Network.players_changed.emit() + +func _on_score_changed() -> void: + Network.players_changed.emit() diff --git a/Game/Player.tscn b/Game/Player.tscn new file mode 100644 index 0000000..38e1d48 --- /dev/null +++ b/Game/Player.tscn @@ -0,0 +1,24 @@ +[gd_scene load_steps=3 format=3 uid="uid://fvspuiqj0osm"] + +[ext_resource type="Script" path="res://Game/Player.gd" id="1_37njm"] + +[sub_resource type="SceneReplicationConfig" id="SceneReplicationConfig_6h1lm"] +properties/0/path = NodePath(".:score") +properties/0/spawn = true +properties/0/replication_mode = 2 +properties/1/path = NodePath(".:username") +properties/1/spawn = true +properties/1/replication_mode = 2 +properties/2/path = NodePath(".:id") +properties/2/spawn = true +properties/2/replication_mode = 0 + +[node name="Player" type="Node"] +script = ExtResource("1_37njm") + +[node name="MultiplayerSynchronizer" type="MultiplayerSynchronizer" parent="."] +replication_config = SubResource("SceneReplicationConfig_6h1lm") + +[connection signal="score_changed" from="." to="." method="_on_score_changed"] +[connection signal="delta_synchronized" from="MultiplayerSynchronizer" to="." method="_on_multiplayer_synchronizer_delta_synchronized"] +[connection signal="synchronized" from="MultiplayerSynchronizer" to="." method="_on_multiplayer_synchronizer_synchronized"] |