summaryrefslogtreecommitdiff
path: root/Game
diff options
context:
space:
mode:
Diffstat (limited to 'Game')
-rw-r--r--Game/Client.gd32
-rw-r--r--Game/Network.gd154
-rw-r--r--Game/Network.tscn13
-rw-r--r--Game/Player.gd33
-rw-r--r--Game/Player.tscn24
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"]