cs-os/scripts/Networking.gd

416 lines
16 KiB
GDScript

extends Node
var player_script := preload("res://scripts/Player.gd")
var server_map
@onready var Weapons = GameData.Weapons
var player_model = preload("res://scenes/models/player.tscn")
var peer = ENetMultiplayerPeer.new()
var settings
var clients = {}
var last_client_id = 1
var map_path
var map_root_name
var spawnpoints_os = []
var spawnpoints_cs = []
func parse_arguments():
var arguments = {}
for argument in OS.get_cmdline_args():
if argument.find("=") > -1:
var key_value = argument.split("=")
arguments[key_value[0].lstrip("--")] = key_value[1]
else:
# Options without an argument will be present in the dictionary,
# with the value set to an empty string.
arguments[argument.lstrip("--")] = ""
return arguments
func _ready():
var arguments = parse_arguments()
if "--server" in OS.get_cmdline_args():
var path
if (arguments.has("map")):
map_root_name = str(arguments["map"])
path = "res://scenes/maps/" + str(arguments["map"]) + ".tscn"
else:
map_root_name = "OffisMi"
path = "res://scenes/maps/OffisMi.tscn"
StartServer(path)
map_path = path
#######################################SERVER####################################
func find_cb3d_by_internal_id(internal_id):
return server_map.get_node("player" + str(internal_id)).find_child("CharacterBody3D")
func StartServer(map_name):
await get_tree().create_timer(0.01).timeout #костыль пиздец но мне похую как-то
if (map_name != null):
get_tree().change_scene_to_file(map_name)
await get_tree().create_timer(0.1).timeout #костыль пиздец но мне похую как-то
var root_node_name = (map_name.split("/")[-1]).split(".")[0]
server_map = get_tree().root.get_node(root_node_name)
await get_tree().create_timer(0.5).timeout #костыль
settings = GameData.server_settings
var port = int(settings["port"])
var maxclients = int(settings["maxclients"])
if (peer.create_server(port, maxclients) != OK):
print("Couldn't create server. Check if another proccess binds port " + str(port))
return
multiplayer.multiplayer_peer = peer
print("Server started")
peer.connect("peer_connected", _Peer_Connected)
peer.connect("peer_disconnected", _Peer_Disconnected)
var spectator = preload("res://scenes/models/spectator.tscn").instantiate()
server_map.add_child(spectator)
var spawnpoints = server_map.find_children("spawnpoint*", "" ,true)
print(str(spawnpoints))
for spawnpoint in spawnpoints:
print("Checking spawnpoint: " + str(spawnpoint) + ", team: " + str(spawnpoint.team))
if spawnpoint.team == 0: # cs
spawnpoints_cs.push_back(spawnpoint)
elif spawnpoint.team > 0: # os
spawnpoints_os.push_back(spawnpoint)
func send_everyone_except(client_id, args):
if (typeof(args[0]) == 4): #string
for current_client_id in clients.keys():
if (str(current_client_id) == str(client_id)): continue
if (args.size() == 1): rpc_id(int(current_client_id), args[0])
elif (args.size() == 2): rpc_id(int(current_client_id), args[0], args[1])
elif (args.size() == 3): rpc_id(int(current_client_id), args[0], args[1], args[2])
else: rpc_id(int(current_client_id), args[0], args[1], args[2], args[3])
else:
for current_client_id in clients.keys():
if (str(current_client_id) == str(client_id)): continue
if (args.size() == 1): args[0].rpc_id(int(current_client_id))
elif (args.size() == 2): args[0].rpc_id(int(current_client_id), args[1])
elif (args.size() == 3): args[0].rpc_id(int(current_client_id), args[1], args[2])
else: args[0].rpc_id(int(current_client_id), args[1], args[2], args[3])
func find_weapon_by_number(number):
var found_weapon
for weapon in settings["game"]["weapons"].keys():
if (settings["game"]["weapons"][weapon]["number"] == number):
found_weapon = settings["game"]["weapons"][weapon].duplicate()
break
return found_weapon
func find_class_type_by_number(number):
var found_class
var classtypes = settings["game"]["classTypes"]
for classtype in classtypes:
if classtypes[classtype]["number"] == number:
found_class = classtypes[classtype].duplicate()
break
return found_class
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] = player_script.new().properties.duplicate()
var client = clients[client_id]
client["position"] = Vector3(0, 10, 0)
client["internal_id"] = internal_id
client["is_playable"] = false
client["current_weapon"] = settings["game"]["weapons"]["knife"].duplicate()
print("New client's properties: " + str(clients[client_id]))
var puppet = player_model.instantiate()
var CB3D = puppet.find_child("CharacterBody3D")
CB3D.set_properties(clients[client_id])
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"]
send_everyone_except(client_id, ["spawn_puppet", clients[client_id]])
client["ready"] = true
var client_cb3d = find_cb3d_by_internal_id(internal_id)
if (client["class_type"] == 0):
var class_spawnpoint = 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"] = spawnpoints_os.pick_random().get_class_spawnpoint(index)
elif (client["class_type"] < 0):
client["position"] = spawnpoints_cs.pick_random().get_class_spawnpoint(index)
client_cb3d.set_properties(client)
client_cb3d.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"]
rpc("despawn_puppet", internal_id)
var puppet = server_map.get_node("player" + str(internal_id))
server_map.remove_child(puppet)
clients.erase(client_id)
@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_cb3d = find_cb3d_by_internal_id(internal_id)
client_cb3d.position = position
client_cb3d.find_child("Head").rotation.y = rotation.y
client_cb3d.find_child("Head").find_child("Camera").rotation.x = rotation.x
client["position"] = position
client["rotation"] = rotation
send_everyone_except(client_id, [client_cb3d.sync_puppet, internal_id, position, rotation])
@rpc ("any_peer", "call_remote", "reliable")
func get_client_list(client_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 ("any_peer", "call_remote", "reliable")
func get_server_settings(client_id):
print("Sending game settings")
var client = clients[client_id]
var internal_id = str(client["internal_id"])
var client_cb3d = find_cb3d_by_internal_id(internal_id)
client_cb3d.set_game_settings.rpc_id(client_id, settings["game"])
@rpc ("any_peer", "call_remote", "reliable")
func set_nickname(client_id, nickname):
print("Got nickname from client: " + str(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 = settings["game"]["weapons"].find_key(find_weapon_by_number(client["current_weapon"]["number"]))
var current_weapon_settings = settings["game"]["weapons"][current_weapon]
var client_cb3d = find_cb3d_by_internal_id(internal_id)
var raycast:RayCast3D = client_cb3d.get_node("Head/Camera/viewRaycast")
var weapon_raycast:RayCast3D = client_cb3d.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_cb3d.position.x) / ((-current_weapon_settings["range"]) - (abs(weapon_raycast.position.z - client_cb3d.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()
if (not target is CharacterBody3D): return
var target_internal_id = int(target.get_node("..").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_cb3d = find_cb3d_by_internal_id(target_internal_id)
var target_client_id = int(clients.find_key(target_client))
var damage = current_weapon_settings["damage"];
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()
target_client["HP"] -= damage
if (target_client["HP"] <= 0):
#target_cb3d.teleport.rpc_id(target_client_id, Vector3(0, 10, 0))
var index = abs(client["class_type"])
var respawn = Vector3(0, 10 ,0)
if (target_client["class_type"] > 0):
respawn = spawnpoints_os.pick_random().get_class_spawnpoint(index)
elif (target_client["class_type"] < 0):
respawn = spawnpoints_cs.pick_random().get_class_spawnpoint(index)
target_client["position"] = respawn
target_client["HP"] = 100
target_cb3d.teleport.rpc_id(target_client_id, target_client["position"])
target_cb3d.set_hp.rpc_id(target_client_id, target_client["HP"])
@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 Weapons.keys():
if (settings["game"]["weapons"][weapon]["number"] == new_weapon_number):
client["current_weapon"] = settings["game"]["weapons"][weapon].duplicate()
break
var client_cb3d = find_cb3d_by_internal_id(internal_id)
client_cb3d.change_weapon(new_weapon_number)
send_everyone_except(client_id, [client_cb3d.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 = settings["game"]["weapons"]
var current_client_weapon = client["current_weapon"]
var current_weapon_example = weapons_list.find_key(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
reloading_complete(client_id, reload_time)
func reloading_complete(client_id, reloading_time):
await get_tree().create_timer(reloading_time).timeout
var client = clients[client_id]
if (!client["reloading"]): # if a client has interrupted the reloading
return
var weapons_list = settings["game"]["weapons"]
var current_client_weapon = client["current_weapon"]
var current_weapon_example = weapons_list.find_key(find_weapon_by_number(current_client_weapon["number"]))
var current_weapon_settings = weapons_list[current_weapon_example]
var to_reload = current_weapon_settings["magazine"] - current_client_weapon["magazine"]
if (to_reload <= current_client_weapon["ammo"]):
current_client_weapon["magazine"] += to_reload
current_client_weapon["ammo"] -= to_reload
else:
current_client_weapon["magazine"] += current_client_weapon["ammo"]
current_client_weapon["ammo"] = 0
@rpc("reliable", "any_peer", "call_remote")
func get_map(client_id):
rpc_id(client_id, "receive_map", 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
#here are must be checks if the teams are balanced. WIP.
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 player_cb3d
@rpc ("reliable", "call_remote")
func set_character_properties(p):
print("Setting player properties to " + str(p))
player = p
@rpc("authority", "reliable", "call_remote")
func spawn_puppet(properties):
var puppet = player_model.instantiate()
var CB3D = puppet.find_child("CharacterBody3D")
properties["ready"] = true
CB3D.set_properties(properties.duplicate())
current_map_instance.add_child(puppet)
@rpc("authority", "reliable", "call_remote")
func despawn_puppet(internal_id):
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):
print("Switching to team: " + str(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)
player_cb3d.set_property("is_playable", true)
player_cb3d.set_property("ready", true)
func spawn_player():
var player_node = player_model.instantiate()
player_cb3d = player_node.find_child("CharacterBody3D")
var properties = player_script.new().properties.duplicate()
properties = player
properties["is_playable"] = false
properties["ready"] = false
player_cb3d.set_properties(properties)
current_map_instance.add_child(player_node)
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)
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