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

251 lines
6.8 KiB
GDScript3
Raw Permalink Normal View History

2020-07-10 13:37:13 +00:00
extends Node
2020-07-12 15:26:40 +00:00
signal ms_updated(action, data)
signal left()
# Hosting info
2020-09-15 23:23:45 +00:00
const SERVER_PORT := 5513
const MAX_PLAYERS := 30
var port := SERVER_PORT
2020-07-12 15:26:40 +00:00
# Throttle network updates of often-changed variables by this many physics frames
2020-09-15 23:23:45 +00:00
const SYSTEMS_UPDATE_INTERVAL := 10
2020-07-12 15:26:40 +00:00
# Master server data
2020-09-15 23:23:45 +00:00
const MASTER_SERVER_ADDR := "fgms.zyg.ovh"
const MASTER_SERVER_UDP_PORT := 9434
const MS_GAME_CODE := "odyssey-0-a2"
const GOTM_OVERRIDE := false
2020-07-12 15:26:40 +00:00
# Master server entry
2020-09-15 23:23:45 +00:00
var ms_active := false
var ms_key := ""
var server_name := ""
2020-07-10 13:37:13 +00:00
2020-09-15 23:23:45 +00:00
var hosting := false
2020-09-15 23:23:45 +00:00
export var player_name := ""
2020-07-12 15:26:40 +00:00
2020-09-15 23:23:45 +00:00
var player_info := {}
var round_info := {}
2020-07-10 13:37:13 +00:00
2020-09-15 23:23:45 +00:00
onready var scene_manager := $"/root/SceneManager"
2020-07-10 13:37:13 +00:00
func _ready():
2020-07-23 08:50:47 +00:00
randomize()
player_name = Names.get_random_name()
2020-07-12 15:26:40 +00:00
func bind_events():
2020-07-10 13:37:13 +00:00
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")
2020-07-12 15:26:40 +00:00
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 #%d)" % failed)
2020-07-12 15:26:40 +00:00
continue
port = socketUDP.get_var(false)
print("Received ", port)
break
socketUDP.close()
func discover_upnp():
2020-09-15 23:23:45 +00:00
var upnp := UPNP.new()
2020-07-12 15:26:40 +00:00
upnp.discover(2000, 2, "InternetGatewayDevice")
return upnp.add_port_mapping(SERVER_PORT)
func host(map_name: String = "odyssey"):
scene_manager.enter_loader()
scene_manager.loading_text = "Starting server"
# Wait just a sec to draw
yield(get_tree().create_timer(0.3), "timeout")
2020-07-14 14:20:06 +00:00
# Run port forwarding/nat punchthrough if the platform doesn't do it already
2020-07-22 15:34:04 +00:00
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")
2020-07-12 15:26:40 +00:00
server_name = "%s's server" % player_name
2020-07-14 14:20:06 +00:00
player_info[1] = { "name": player_name }
round_info = { "map": map_name }
2020-07-14 14:20:06 +00:00
2020-07-12 15:26:40 +00:00
bind_events()
2020-09-15 23:23:45 +00:00
var peer := NetworkedMultiplayerENet.new()
2020-07-20 09:15:39 +00:00
peer.compression_mode = NetworkedMultiplayerENet.COMPRESS_FASTLZ
2020-09-15 23:23:45 +00:00
var server_res := peer.create_server(port, MAX_PLAYERS)
2020-07-12 15:26:40 +00:00
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
2020-07-10 13:37:13 +00:00
print("Hosting")
hosting = true
scene_manager.loading_text = null
2020-07-12 15:26:40 +00:00
scene_manager.load_scene("res://Scenes/Game.tscn", [
"res://Scenes/Maps/%s.tscn" % map_name
])
2020-07-12 15:26:40 +00:00
2020-07-22 15:34:04 +00:00
# Add to master server after hosting
create_ms_entry()
2020-07-10 13:37:13 +00:00
2020-07-14 14:20:06 +00:00
func join(server):
scene_manager.enter_loader()
2020-07-14 14:20:06 +00:00
scene_manager.loading_text = "Joining server"
# Wait just a sec to draw
yield(get_tree().create_timer(0.3), "timeout")
2020-07-12 15:26:40 +00:00
bind_events()
2020-07-10 13:37:13 +00:00
var peer = NetworkedMultiplayerENet.new()
2020-07-22 15:34:04 +00:00
peer.compression_mode = NetworkedMultiplayerENet.COMPRESS_FASTLZ
2020-07-14 14:20:06 +00:00
2020-07-22 15:34:04 +00:00
var addr = server.address
2020-07-14 14:20:06 +00:00
2020-07-10 13:37:13 +00:00
peer.create_client(addr, SERVER_PORT)
get_tree().network_peer = peer
print("Connecting to %s" % addr)
2020-07-10 13:37:13 +00:00
func leave():
2020-09-15 23:23:45 +00:00
var peer := get_tree().network_peer
2020-07-10 13:37:13 +00:00
if get_tree().is_network_server():
2020-07-12 15:26:40 +00:00
# Tell MS we're leaving
if ms_active:
_ms_request("remove", { "key": ms_key })
yield(self, "ms_updated")
2020-07-10 13:37:13 +00:00
elif peer != null:
#TODO Send leave message
pass
get_tree().network_peer = null
2020-07-12 15:26:40 +00:00
emit_signal("left")
2020-07-10 13:37:13 +00:00
func _player_connected(id):
rpc_id(id, "register_player", player_name)
if get_tree().is_network_server():
rpc_id(id, "_handshake", { "round": round_info, "players": player_info })
2020-07-10 13:37:13 +00:00
func _player_disconnected(id):
print("%s (%d) disconnected" % [player_info[id].name, id])
2020-07-10 13:37:13 +00:00
player_info.erase(id)
func _connected_ok():
print("Connected to server")
scene_manager.loading_text = null
scene_manager.load_scene("res://Scenes/Game.tscn", [])
2020-07-10 13:37:13 +00:00
func _server_disconnected():
print("Disconnected from server")
func _connected_fail():
2020-07-12 15:26:40 +00:00
push_warning("Connection failed")
2020-07-10 13:37:13 +00:00
remote func register_player(username: String):
2020-09-15 23:23:45 +00:00
var id := get_tree().get_rpc_sender_id()
2020-07-10 13:37:13 +00:00
player_info[id] = { name=username }
print("%s (%d) connected" % [player_info[id].name, id])
2020-07-10 13:37:13 +00:00
remote func _handshake(infos):
round_info = infos["round"]
player_info = infos["players"]
2020-07-12 15:26:40 +00:00
func _ms_request(endpoint: String, data):
2020-09-15 23:23:45 +00:00
var http_request := HTTPRequest.new()
2020-07-12 15:26:40 +00:00
add_child(http_request)
http_request.connect("request_completed", self, "_ms_response", [endpoint])
print_debug("Telling ms to %s" % endpoint)
2020-07-12 15:26:40 +00:00
var error = http_request.request(
"https://%s/%s" % [MASTER_SERVER_ADDR, endpoint],
2020-07-12 15:26:40 +00:00
["Content-Type: application/json"],
true, HTTPClient.METHOD_POST, JSON.print(data))
if error != OK:
push_error("An error occurred in the HTTP request.")
2020-07-13 23:59:45 +00:00
func ms_get_entries():
2020-09-15 23:23:45 +00:00
var http_request := HTTPRequest.new()
2020-07-22 15:34:04 +00:00
add_child(http_request)
http_request.connect("request_completed", self, "_ms_response", ["list_games"])
var error = http_request.request(
"https://%s/%s" % [MASTER_SERVER_ADDR, MS_GAME_CODE],
2020-07-22 15:34:04 +00:00
["Content-Type: application/json"],
true, HTTPClient.METHOD_GET)
if error != OK:
push_error("An error occurred in the HTTP request.")
2020-07-13 23:59:45 +00:00
2020-07-12 15:26:40 +00:00
func get_game_data():
return {
"name": server_name,
"port": port,
"max_players": MAX_PLAYERS,
"players": player_info.size()
}
func create_ms_entry():
2020-07-22 15:34:04 +00:00
_ms_request("new", {
"game_id": MS_GAME_CODE,
"data": get_game_data()
})
2020-07-12 15:26:40 +00:00
func update_ms_entry():
2020-07-22 15:34:04 +00:00
if ms_active:
_ms_request("update", {
"key": ms_key,
"data": get_game_data()
})
2020-07-13 23:59:45 +00:00
var time_left = 30
func _process(delta):
if not ms_active:
return
time_left -= delta
if time_left < 0:
update_ms_entry()
time_left = 30
2020-07-12 15:26:40 +00:00
func _ms_response(_result: int, response_code: int, _headers: PoolStringArray, body: PoolByteArray, action: String):
print_debug("MS said %s" % response_code)
2020-07-12 15:26:40 +00:00
if response_code > 299:
push_error("ms action '%s' returned error: %s - %s" % [action, response_code, body.get_string_from_utf8()])
2020-07-12 15:26:40 +00:00
return
2020-09-15 23:23:45 +00:00
var json := JSON.parse(body.get_string_from_utf8())
2020-07-12 15:26:40 +00:00
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")
func get_current_map():
match round_info.map:
"odyssey":
return GameWorld.Map.ODYSSEY
"runtime":
return GameWorld.Map.RUNTIME
_:
return GameWorld.Map.EMPTY