extends Node var player_script = load("res://scripts/Player.gd") var player_model = load("res://scenes/models/player.tscn") var peer = ENetMultiplayerPeer.new() var clients:Dictionary = {} var last_client_id = 1 #######################################SERVER#################################### func StartServer(): var port = int(GameData.server_settings["port"]) var maxclients = int(GameData.server_settings["maxclients"]) if (peer.create_server(port, maxclients) != OK): print("Couldn't create server. Check if another proccess binds port %s" % str(port)) return multiplayer.multiplayer_peer = peer print("Server started") peer.connect("peer_connected", _Peer_Connected) peer.connect("peer_disconnected", _Peer_Disconnected) func _Peer_Connected(client_id): print("User " + str(client_id) + " has conected") var internal_id = last_client_id + 1 last_client_id += 1 clients[client_id] = GameData.properties_example.duplicate() var client = clients[client_id] client["position"] = Vector3(0, 10, 0) client["internal_id"] = internal_id client["is_playable"] = false client["current_weapon"] = GameData.server_settings["game"]["weapons"]["knife"].duplicate() var puppet = player_model.instantiate() puppet.set_properties(clients[client_id]) ServerUtils.server_map.add_child(puppet) @rpc("any_peer", "reliable", "call_remote") func client_ready(client_id): var client = clients[client_id] var internal_id = client["internal_id"] NetUtils.send_everyone_except(client_id, [Networking.spawn_puppet, clients[client_id]]) client["ready"] = true var client_playermodel = ServerUtils.find_playermodel_by_internal_id(internal_id) if (client["class_type"] == 0): var class_spawnpoint = ServerUtils.find_class_type_by_number(client["class_type"])["spawnpoint"] client["position"] = Vector3(class_spawnpoint[0], class_spawnpoint[1], class_spawnpoint[2]) else: var index = abs(client["class_type"]) if (client["class_type"] > 0): client["position"] = ServerUtils.team_OS["spawnpoints"].pick_random().get_class_spawnpoint(index) elif (client["class_type"] < 0): client["position"] = ServerUtils.team_CS["spawnpoints"].pick_random().get_class_spawnpoint(index) client_playermodel.set_properties(client) client_playermodel.teleport.rpc_id(client_id, Vector3(client["position"].x, client["position"].y, client["position"].z)) func _Peer_Disconnected(client_id): print("User " + str(client_id) + " has disconnected") var client = clients[client_id] var internal_id = client["internal_id"] if (client["class_type"] < 0): ServerUtils.team_CS["members"].erase(client) elif (client["class_type"] > 0): ServerUtils.team_OS["members"].erase(client) rpc("despawn_puppet", internal_id) var puppet = ServerUtils.server_map.get_node("player" + str(internal_id)) ServerUtils.server_map.remove_child(puppet) clients.erase(client_id) if (clients.size() == 0): ServerUtils.new_game(null, null) #Not changing anything @rpc ("any_peer", "reliable", "call_remote") func get_character_properties(client_id): if !clients.has(client_id): return var to_send = clients[client_id] rpc_id(client_id, "set_character_properties", to_send.duplicate()) @rpc("any_peer", "call_remote", "unreliable") func sync_client(client_id, position, rotation): var client = clients[client_id] var internal_id = str(client["internal_id"]) var client_playermodel = ServerUtils.find_playermodel_by_internal_id(internal_id) client_playermodel.position = position #client_playermodel.find_child("Head").rotation.y = rotation.y client_playermodel.rotation.y = rotation.y client_playermodel.find_child("Head").find_child("Camera").rotation.x = rotation.x client["position"] = position client["rotation"] = rotation #NetUtils.send_everyone_except(client_id, ["sync_puppet", internal_id, position, rotation]) NetUtils.send_everyone_except(client_id, [client_playermodel.sync_puppet, internal_id, position, rotation]) @rpc ("any_peer", "call_remote", "reliable") func get_client_list(client_id): #var playermodel = ServerUtils.find_playermodel_by_internal_id(clients[client_id]["internal_id"]) for current_client_id in clients.keys(): if (current_client_id == client_id): continue rpc_id(client_id, "spawn_puppet", clients[current_client_id]) #rpc_id(client_id, playermodel.spawn_puppet, clients[current_client_id]) @rpc ("any_peer", "call_remote", "reliable") func get_server_settings(client_id): var client = clients[client_id] var internal_id = str(client["internal_id"]) var client_playermodel = ServerUtils.find_playermodel_by_internal_id(internal_id) client_playermodel.set_game_settings.rpc_id(client_id, GameData.server_settings["game"]) @rpc ("any_peer", "call_remote", "reliable") func set_nickname(client_id, nickname): clients[client_id]["nickname"] = nickname @rpc("any_peer", "call_remote", "reliable") func shot(client_id): var client = clients[client_id] var internal_id = client["internal_id"] var current_weapon = GameData.server_settings["game"]["weapons"].find_key(ServerUtils.find_weapon_by_number(client["current_weapon"]["number"])) var current_weapon_settings = GameData.server_settings["game"]["weapons"][current_weapon] var client_playermodel = ServerUtils.find_playermodel_by_internal_id(internal_id) var raycast:RayCast3D = client_playermodel.get_node("Head/Camera/viewRaycast") var weapon_raycast:RayCast3D = client_playermodel.get_node("Head/Camera/Hand/" + str(current_weapon) + "/raycast") raycast.target_position.z = -current_weapon_settings["range"] raycast.force_raycast_update() raycast.force_update_transform() var target_point = raycast.get_collision_point() weapon_raycast.target_position = weapon_raycast.to_local(target_point) * 1.1 weapon_raycast.rotation.y = atan((weapon_raycast.position.x - client_playermodel.position.x) / ((-current_weapon_settings["range"]) - (abs(weapon_raycast.position.z - client_playermodel.position.z)))) weapon_raycast.target_position.y += current_weapon_settings["spreading"] * randf() * sin(randf() * 2 * PI) weapon_raycast.target_position.z += current_weapon_settings["spreading"] * randf() * cos(randf() * 2 * PI) weapon_raycast.force_raycast_update() weapon_raycast.force_update_transform() var target = weapon_raycast.get_collider() var time_since_last_shot = (Time.get_ticks_msec() - client["last_shot"]) / 1000. if (time_since_last_shot < current_weapon_settings["fireRate"] and client["last_shot"] > 0): return if (client["current_weapon"]["magazine"] == 0): return client["last_shot"] = Time.get_ticks_msec() if (target is CharacterBody3D): var target_internal_id = int(target.name.get_slice("player", 1)) var target_client for checking_client_id in clients.keys(): if (clients[checking_client_id]["internal_id"] == target_internal_id): target_client = clients[checking_client_id] var target_client_id = int(clients.find_key(target_client)) var shape_num = weapon_raycast.get_collider_shape() var shapes = ["head", "body", "hand", "leg"] var shape = ServerUtils.choose_collision_shape(target, shape_num) var damage for s in shapes: if s in shape.name: damage = current_weapon_settings["damage"][s] break var target_client_team = 1 if target_client["class_type"] > 0 else -1 var client_team = 1 if client["class_type"] > 0 else -1 if (target_client_team == client_team): if (GameData.server_settings["game"]["gamemodes"][str(ServerUtils.gamemode)]["friendlyfire"]): target_client["HP"] -= damage else: target_client["HP"] -= damage if (target_client["HP"] <= 0): ###########killed var index = abs(client["class_type"]) var respawn = Vector3(0, 10 ,0) if (target_client_team == 1): ServerUtils.team_CS["round_score"] += 1 respawn = ServerUtils.team_OS["spawnpoints"].pick_random().get_class_spawnpoint(index) elif (target_client_team == -1): ServerUtils.team_OS["round_score"] += 1 respawn = ServerUtils.team_CS["spawnpoints"].pick_random().get_class_spawnpoint(index) print("Score(OS-CS): %s - %s" % [str(ServerUtils.team_OS["round_score"]), str(ServerUtils.team_CS["round_score"])]) target_client["position"] = respawn target_client["HP"] = 100 target.teleport.rpc_id(target_client_id, target_client["position"]) NetUtils.send_everyone(["kill_notification", client["nickname"], target_client["nickname"]]) ServerUtils.check_gamemode_end_conditions() target.set_hp.rpc_id(target_client_id, target_client["HP"]) elif (target is StaticBody3D): #var shapes = ["head", "body"] #var shape_num = weapon_raycast.get_collider_shape() #var shape = ServerUtils.choose_collision_shape(target, shape_num) target.shot.rpc_id(client_id, weapon_raycast.get_collision_point()) NetUtils.send_everyone_except(client_id, [target.shot, weapon_raycast.get_collision_point()]) @rpc("reliable", "call_remote", "any_peer") func change_weapon(client_id, new_weapon_number): var client = clients[client_id] client["reloading"] = false var internal_id = str(client["internal_id"]) for weapon in GameData.Weapons.keys(): if (GameData.server_settings["game"]["weapons"][weapon]["number"] == new_weapon_number): client["current_weapon"] = GameData.server_settings["game"]["weapons"][weapon].duplicate() break var client_playermodel = ServerUtils.find_playermodel_by_internal_id(internal_id) client_playermodel.change_weapon(new_weapon_number) #NetUtils.send_everyone_except(client_id, ["change_weapon_puppet", internal_id, new_weapon_number]) NetUtils.send_everyone_except(client_id, [client_playermodel.change_weapon_puppet, internal_id, new_weapon_number]) @rpc("any_peer", "call_remote", "reliable") func client_reloading(client_id): var client = clients[client_id] var weapons_list = GameData.server_settings["game"]["weapons"] var current_client_weapon = client["current_weapon"] var current_weapon_example = weapons_list.find_key(ServerUtils.find_weapon_by_number(current_client_weapon["number"])) var current_weapon_settings = weapons_list[current_weapon_example] var reload_time = current_weapon_settings["reload"] client["reloading"] = true ServerUtils.reloading_complete(client_id, reload_time) @rpc("reliable", "any_peer", "call_remote") func get_map(client_id): rpc_id(client_id, "receive_map", ServerUtils.map_path) @rpc("reliable", "any_peer", "call_remote") func choose_class(client_id, class_id): var client = clients[client_id] client["class_type"] = class_id #client["HP"] = GameData.settings["game"]["classes"][class_id]["HP"] #here are must be checks if the teams are balanced. WIP. if class_id > 0: ServerUtils.team_OS["members"].push_back(client) elif class_id < 0: ServerUtils.team_CS["members"].push_back(client) switch_class.rpc_id(client_id, class_id) ##########################################CLIENT####################### var player var menu = preload("res://scenes/HUD/menu.tscn") var current_map_instance var choose_team_hud var playermodel var puppets_to_spawn = [] var map_path var map_root_name @rpc ("reliable", "call_remote") func set_character_properties(p): player = p @rpc("authority", "reliable", "call_remote") func spawn_puppet(properties): if (current_map_instance == null): # Player's not ready puppets_to_spawn.push_back(properties) return var puppet = player_model.instantiate() properties["ready"] = true puppet.set_properties(properties.duplicate()) current_map_instance.add_child(puppet) func spawn_puppet_onready(properties): var puppet = player_model.instantiate() properties["ready"] = true puppet.set_properties(properties.duplicate()) current_map_instance.add_child(puppet) @rpc("authority", "reliable", "call_remote") func despawn_puppet(internal_id): if (current_map_instance == null): return var puppet = current_map_instance.get_node("player" + str(internal_id)) current_map_instance.remove_child(puppet) @rpc("authority", "reliable", "call_remote") func receive_map(p): map_path = p map_root_name = (map_path.split("/")[-1]).split(".")[0] @rpc("authority", "reliable", "call_remote") func switch_class(class_id): if (class_id == 128): # team is full, you must chose another current_map_instance.remove_child(choose_team_hud) current_map_instance.add_child(choose_team_hud) player["class_type"] = class_id rpc_id(1, "client_ready", multiplayer.get_unique_id()) current_map_instance.remove_child(choose_team_hud) playermodel.set_property("is_playable", true) playermodel.set_property("ready", true) func spawn_player(): print(str(player_model)) playermodel = player_model.instantiate() print(str(playermodel)) var properties = GameData.properties_example.duplicate() properties = player properties["is_playable"] = false properties["ready"] = false playermodel.set_properties(properties) current_map_instance.add_child(playermodel) func ConnectToServer(ip, port): peer.create_client(ip, port) multiplayer.multiplayer_peer = peer if not multiplayer.connected_to_server.is_connected(_Connection_Succseeded): multiplayer.connected_to_server.connect(_Connection_Succseeded) if not multiplayer.connection_failed.is_connected(_Connection_Failed): multiplayer.connection_failed.connect(_Connection_Failed) if not multiplayer.server_disconnected.is_connected(_Server_Disconnected): multiplayer.server_disconnected.connect(_Server_Disconnected) func _Connection_Failed(): print("Failed to connect to server") multiplayer.multiplayer_peer = null peer = ENetMultiplayerPeer.new() multiplayer.multiplayer_peer = peer func _Connection_Succseeded(): print("Succsessfully connected to the server") var nickname = GameData.client_settings["nickname"] rpc_id(1, "set_nickname", multiplayer.get_unique_id(), nickname) rpc_id(1, "get_character_properties", multiplayer.get_unique_id()) rpc_id(1, "get_map", multiplayer.get_unique_id()) await get_tree().create_timer(0.2).timeout # костыль get_tree().change_scene_to_file(map_path) await get_tree().create_timer(1).timeout # костыль current_map_instance = get_tree().root.get_node(map_root_name) rpc_id(1, "get_client_list", multiplayer.get_unique_id()) await get_tree().create_timer(0.05).timeout # костыль # tp rpc_id(1, "get_server_settings", multiplayer.get_unique_id()) await spawn_player() choose_team_hud = preload("res://scenes/HUD/choose_team.tscn").instantiate() current_map_instance.add_child(choose_team_hud) for puppet in puppets_to_spawn: spawn_puppet_onready(puppet) func _Server_Disconnected(): print("Server has disconnected") Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE) get_tree().change_scene_to_file("res://scenes/HUD/menu.tscn") multiplayer.multiplayer_peer = null peer = ENetMultiplayerPeer.new() multiplayer.multiplayer_peer = peer