gamestate.gd 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. extends Node
  2. # Default game server port. Can be any number between 1024 and 49151.
  3. # Not on the list of registered or common ports as of May 2024:
  4. # https://en.wikipedia.org/wiki/List_of_TCP_and_UDP_port_numbers
  5. const DEFAULT_PORT = 10567
  6. ## The maximum number of players.
  7. const MAX_PEERS = 12
  8. var peer: ENetMultiplayerPeer
  9. ## Our local player's name.
  10. var player_name := "The Warrior"
  11. # Names for remote players in id:name format.
  12. var players := {}
  13. var players_ready: Array[int] = []
  14. # Signals to let lobby GUI know what's going on.
  15. signal player_list_changed()
  16. signal connection_failed()
  17. signal connection_succeeded()
  18. signal game_ended()
  19. signal game_error(what: int)
  20. # Callback from SceneTree.
  21. func _player_connected(id: int) -> void:
  22. # Registration of a client beings here, tell the connected player that we are here.
  23. register_player.rpc_id(id, player_name)
  24. # Callback from SceneTree.
  25. func _player_disconnected(id: int) -> void:
  26. if has_node("/root/World"):
  27. # Game is in progress.
  28. if multiplayer.is_server():
  29. game_error.emit("Player " + players[id] + " disconnected")
  30. end_game()
  31. else:
  32. # Game is not in progress.
  33. # Unregister this player.
  34. unregister_player(id)
  35. # Callback from SceneTree, only for clients (not server).
  36. func _connected_ok() -> void:
  37. # We just connected to a server
  38. connection_succeeded.emit()
  39. # Callback from SceneTree, only for clients (not server).
  40. func _server_disconnected() -> void:
  41. game_error.emit("Server disconnected")
  42. end_game()
  43. # Callback from SceneTree, only for clients (not server).
  44. func _connected_fail() -> void:
  45. multiplayer.set_network_peer(null) # Remove peer
  46. connection_failed.emit()
  47. # Lobby management functions.
  48. @rpc("any_peer")
  49. func register_player(new_player_name: String) -> void:
  50. var id := multiplayer.get_remote_sender_id()
  51. players[id] = new_player_name
  52. player_list_changed.emit()
  53. func unregister_player(id: int) -> void:
  54. players.erase(id)
  55. player_list_changed.emit()
  56. @rpc("call_local")
  57. func load_world() -> void:
  58. # Change scene.
  59. var world: Node2D = load("res://world.tscn").instantiate()
  60. get_tree().get_root().add_child(world)
  61. get_tree().get_root().get_node("Lobby").hide()
  62. # Set up score.
  63. world.get_node("Score").add_player(multiplayer.get_unique_id(), player_name)
  64. for pn: int in players:
  65. world.get_node("Score").add_player(pn, players[pn])
  66. # Unpause and unleash the game!
  67. get_tree().paused = false
  68. func host_game(new_player_name: String) -> void:
  69. player_name = new_player_name
  70. peer = ENetMultiplayerPeer.new()
  71. peer.create_server(DEFAULT_PORT, MAX_PEERS)
  72. multiplayer.set_multiplayer_peer(peer)
  73. func join_game(ip: String, new_player_name: String) -> void:
  74. player_name = new_player_name
  75. peer = ENetMultiplayerPeer.new()
  76. peer.create_client(ip, DEFAULT_PORT)
  77. multiplayer.set_multiplayer_peer(peer)
  78. func get_player_list() -> Array:
  79. return players.values()
  80. func begin_game() -> void:
  81. assert(multiplayer.is_server())
  82. load_world.rpc()
  83. var world: Node2D = get_tree().get_root().get_node("World")
  84. var player_scene: PackedScene = load("res://player.tscn")
  85. # Create a dictionary with peer ID. and respective spawn points.
  86. # TODO: This could be improved by randomizing spawn points for players.
  87. var spawn_points := {}
  88. spawn_points[1] = 0 # Server in spawn point 0.
  89. var spawn_point_idx := 1
  90. for p: int in players:
  91. spawn_points[p] = spawn_point_idx
  92. spawn_point_idx += 1
  93. for p_id: int in spawn_points:
  94. var spawn_pos: Vector2 = world.get_node("SpawnPoints/" + str(spawn_points[p_id])).position
  95. var player := player_scene.instantiate()
  96. player.synced_position = spawn_pos
  97. player.name = str(p_id)
  98. world.get_node("Players").add_child(player)
  99. # The RPC must be called after the player is added to the scene tree.
  100. player.set_player_name.rpc(player_name if p_id == multiplayer.get_unique_id() else players[p_id])
  101. func end_game() -> void:
  102. if has_node("/root/World"):
  103. # If the game is in progress, end it.
  104. get_node("/root/World").queue_free()
  105. game_ended.emit()
  106. players.clear()
  107. func _ready() -> void:
  108. multiplayer.peer_connected.connect(_player_connected)
  109. multiplayer.peer_disconnected.connect(_player_disconnected)
  110. multiplayer.connected_to_server.connect(_connected_ok)
  111. multiplayer.connection_failed.connect(_connected_fail)
  112. multiplayer.server_disconnected.connect(_server_disconnected)
  113. ## Returns an unique-looking player color based on the name's hash.
  114. func get_player_color(p_name: String) -> Color:
  115. return Color.from_hsv(wrapf(p_name.hash() * 0.001, 0.0, 1.0), 0.6, 1.0)