extends Node var world var motd : String var server_name : String var player_limit : int var connected_player_count : int = 0 var connected_players = {} enum {PLAYER_NAME, PLAYER_TEAM} var server_enet : NetworkedMultiplayerENet var output var output_func : String func print_line(line): if output == null: print("SERVER: " + line) return output.call(output_func, line) func _ready(): var signal_status = [ get_tree().connect("network_peer_connected", self, "_client_connect"), get_tree().connect("network_peer_disconnected", self, "_client_disconnect")] for sig in signal_status: if sig != OK: print("SERVER: Error connecting one or more signals. Error code: " + str(sig)) func start_server(_server_name: String, _motd: String, max_players: int, map_path: String, _ip: String, port: int, tree, output_obj, output_f): output = output_obj output_func = output_f server_name = _server_name motd = _motd player_limit = max_players server_enet = NetworkedMultiplayerENet.new() var srv_stat = server_enet.create_server(port, max_players) if srv_stat != OK: print_line("Error creating server. Code: "+str(srv_stat)) stop_server() return tree.set_network_peer(server_enet) world = load(map_path) if world: world = world.instance() else: print_line("Error loading map.") return world.add_child(self) tree.get_root().add_child(world) world.client_id = 1 print_line("Server started successfully.") NavigationServer.set_active(false) func stop_server(): print_line("Shutting down server...") server_enet.close_connection() print_line("Shut down successfully.") world.queue_free() func _client_disconnect(id): print_line("Client (ID: "+str(id)+") has disconnected.") for character in world.get_node("PLAYERS").get_children(): if character.get_network_master() == id: character.rpc("set_owner", 1) connected_players.erase(id) connected_player_count -= 1 world.rpc("update_players_info", connected_players) func _client_connect(id): print_line("Client (ID: "+str(id)+") connecting...") connected_player_count += 1 connected_players[id] = ["", "SPEC"] #Placeholder for name var server_info = {"player_count" : connected_player_count, "server_name" : server_name, "MOTD" : motd, "cam_pos" : world.get_node("DEFAULTCAM").transform} world.rpc_id(id, "set_up_server_info", server_info) var geo_info = [] for world_geo in world.get_node("WORLDGEO").get_children(): geo_info.append( { "filename" : world_geo.filename, "transform" : world_geo.transform }) world.rpc_id(id, "load_map", geo_info) var ent_info = [] for section in ["PLAYERS","MACHINES","BALLISTICS"]: for item in world.get_node(section).get_children(): ent_info.append({"type" : section, "net_master" : item.get_network_master(), "name" : item.name, "filename" : item.filename, "transform" : item.transform, "init_info" : item.get_init_info() }) world.rpc_id(id, "load_entities", ent_info) func _client_connection_confirmed(arguments): print_line("Client (ID: "+str(arguments["id"])+") connected as " +arguments["username"] +".") connected_players[arguments["id"]] = [arguments["username"], "SPEC"] world.rpc("update_players_info", connected_players) func _client_change_teams(arguments): print_line(connected_players[arguments["id"]][PLAYER_NAME] + " ("+ str(arguments["id"]) +") changed to team " + arguments["team"]) connected_players[arguments["id"]][PLAYER_TEAM] = arguments["team"] world.rpc("update_players_info", connected_players) func _client_request_change_character(arguments): var dest = world.get_node("PLAYERS/"+arguments["char_name"]) if dest != null and dest.get_network_master() == 1: print_line(connected_players[arguments["id"]][PLAYER_NAME] + " selected character " + arguments["char_name"]) dest.rpc("set_net_owner", arguments["id"]) if arguments["current_char_name"] != "NULL": var old = world.get_node("PLAYERS/"+arguments["current_char_name"]) old.rpc("set_net_owner", int(1)) func _client_request_control_vehicle(arguments): var dest_machine = world.get_node(arguments["machine_path"]) var name = "BOT" if arguments["id"] == 1 else connected_players[arguments["id"]][PLAYER_NAME] if dest_machine != null and dest_machine.get_network_master() == 1 and !dest_machine.in_use: print_line(arguments["char_name"] + "(" + name + ") is controlling " + dest_machine.name) dest_machine.rpc("set_net_owner", arguments["id"], arguments["char_name"]) func _character_death(arguments): if world.get_node("PLAYERS/"+arguments["victim_name"]) == null: return var victim_player: String = connected_players[arguments["victim_mp_id"]][PLAYER_NAME] if arguments["victim_mp_id"] != 1 else arguments["victim_name"] var killer_player: String = connected_players[arguments["killer_id"]][PLAYER_NAME] if arguments["killer_id"] != 1 else arguments["killer_name"] print_line(victim_player+" killed by " +killer_player+ " using " + arguments["extra"] + ".") world.rpc("game_chat_msg", victim_player+" killed by " +killer_player+ " using " + arguments["extra"] + ".") world.get_node("PLAYERS/"+arguments["victim_name"]).rpc("remove_dead_character") world.rpc("game_update_chars") func _send_chat(arguments): if !("name" in arguments): arguments["name"]=connected_players[arguments["id"]][PLAYER_NAME] print_line(arguments["name"]+ ": " + arguments["msg"]) world.rpc("game_chat_msg", arguments["name"]+ ": " + arguments["msg"]) func _set_ai_state(args): var charname: String = args[0] var state: String = args[1] print(args) var man: NetChar = world.get_node("PLAYERS/"+charname) if man: man.ai_set_state(state)