This repository has been archived on 2020-09-30. You can view files and clone it, but cannot push or open issues or pull requests.
odyssey-old/Scenes/Global/Multiplayer.gd
2020-07-12 17:26:40 +02:00

189 lines
5.2 KiB
GDScript

extends Node
signal ms_updated(action, data)
signal left()
# Hosting info
const SERVER_PORT = 5513
const MAX_PLAYERS = 30
var port = SERVER_PORT
# Master server data
const MASTER_SERVER_ADDR = "fgms.zyg.ovh"
const MASTER_SERVER_UDP_PORT = 9434
const MS_GAME_CODE = "odyssey-0-a1"
# Master server entry
var ms_active = false
var ms_key = ""
var server_name = ""
export var player_name = ""
var player_info = {}
func _ready():
player_name = "tider-" + str(randi() % 1000)
func bind_events():
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")
func punch_nat():
var socketUDP = PacketPeerUDP.new()
if socketUDP.listen(SERVER_PORT) != OK:
push_error("error listening on port: " + str(SERVER_PORT))
socketUDP.set_dest_address(MASTER_SERVER_ADDR, MASTER_SERVER_UDP_PORT)
socketUDP.put_packet("hi server!".to_ascii())
# Poll for answer from server, since godot doesn't have events for UDP packets (ノへ ̄、)
var failed = 0
while failed < 5:
yield(get_tree().create_timer(.3), "timeout")
if socketUDP.get_available_packet_count() < 1:
failed += 1
print("no reply (attempt #", failed, ")")
continue
port = socketUDP.get_var(false)
print("Received ", port)
break
socketUDP.close()
func discover_upnp():
var upnp = UPNP.new()
upnp.discover(2000, 2, "InternetGatewayDevice")
return upnp.add_port_mapping(SERVER_PORT)
func host():
print("Running UPNP magicks")
if discover_upnp() == UPNP.UPNP_RESULT_SUCCESS:
print("UPNP mapping added")
else:
push_warning("UPNP magicks fail, punching NAT in the face")
yield(punch_nat(), "completed")
bind_events()
var peer = NetworkedMultiplayerENet.new()
var server_res = peer.create_server(port, MAX_PLAYERS)
if server_res != OK:
match server_res:
ERR_CANT_CREATE:
push_error("Can't create server")
ERR_ALREADY_IN_USE:
push_error("Already in use")
return
get_tree().network_peer = peer
print("Hosting")
server_name = player_name + "'s server"
player_info[1] = { name=player_name }
get_tree().change_scene("res://Scenes/Game.tscn")
# Add to master server
create_ms_entry()
func join(addr: String):
bind_events()
var peer = NetworkedMultiplayerENet.new()
peer.create_client(addr, SERVER_PORT)
get_tree().network_peer = peer
print("Connecting to ", addr)
func leave():
var peer = get_tree().network_peer
if get_tree().is_network_server():
# Tell MS we're leaving
if ms_active:
_ms_request("remove", { "key": ms_key })
yield(self, "ms_updated")
elif peer != null:
#TODO Send leave message
pass
get_tree().network_peer = null
emit_signal("left")
func _player_connected(id):
rpc_id(id, "register_player", player_name)
if get_tree().is_network_server():
pass
#rpc_id(id, "spawn_players", mapLoader.map.all_players())
func _player_disconnected(id):
print(player_info[id].name, " (", id, ") disconnected")
player_info.erase(id)
func _connected_ok():
print("Connected to server")
func _server_disconnected():
print("Disconnected from server")
func _connected_fail():
push_warning("Connection failed")
remote func register_player(username: String):
var id = get_tree().get_rpc_sender_id()
player_info[id] = { name=username }
print(player_info[id].name, " (", id, ") connected")
remote func spawn_players(players):
for player_id in players:
pass
#mapLoader.map.spawn_player(player_id)
# Spawn myself as well
#mapLoader.map.rpc("spawn_player", get_tree().network_peer.get_unique_id())
func _ms_request(endpoint: String, data):
var http_request = HTTPRequest.new()
add_child(http_request)
http_request.connect("request_completed", self, "_ms_response", [endpoint])
print_debug("Telling ms to " + endpoint)
var error = http_request.request(
"https://" + MASTER_SERVER_ADDR + "/" + endpoint,
["Content-Type: application/json"],
true, HTTPClient.METHOD_POST, JSON.print(data))
if error != OK:
push_error("An error occurred in the HTTP request.")
func get_game_data():
return {
"name": server_name,
"port": port,
"max_players": MAX_PLAYERS,
"players": player_info.size()
}
func create_ms_entry():
_ms_request("new", {
"game_id": MS_GAME_CODE,
"data": get_game_data()
})
update_ms_entry()
func update_ms_entry():
if ms_active:
_ms_request("update", {
"key": ms_key,
"data": get_game_data()
})
yield(get_tree().create_timer(20), "timeout")
func _ms_response(_result: int, response_code: int, _headers: PoolStringArray, body: PoolByteArray, action: String):
print_debug("MS said " + str(response_code))
if response_code > 299:
push_error("ms action \"" + action + "\" returned error: " + str(response_code) + " - " + body.get_string_from_utf8())
return
var json = JSON.parse(body.get_string_from_utf8())
match action:
"new":
if json.result.ok:
ms_active = true
ms_key = json.result.key
emit_signal("ms_updated", action, json.result)
func _notification(what):
# Are we quittin son?
if what == MainLoop.NOTIFICATION_WM_QUIT_REQUEST:
leave()
yield(self, "left")