extends Node2D var nakama_client: NakamaClient var nakama_session: NakamaSession var nakama_socket: NakamaSocket @export var player: Player var predicted_tick = 0 var delta_counter = 0 var bullet_lerp_factor := 0.0 var bullets = [] var current_match_id = "" func _ready() -> void: child_exiting_tree.connect(_on_child_exiting_tree) print("Attempting auth.") await attempt_auth() print("Attempting to create debug match.") await create_and_join_debug_match() nakama_socket.received_match_state.connect(self._on_match_state) func _process(delta: float) -> void: if current_match_id == "": return predict_tick_and_broadcast(delta) for bullet in bullets: var prev_pos = bullet.get_current_pos(predicted_tick) var next_pos = bullet.get_current_pos(predicted_tick + 1) var interpolated_pos = prev_pos.lerp(next_pos, bullet_lerp_factor) bullet.position = interpolated_pos if bullet.beyond_kill_boundary(predicted_tick): bullet.queue_free() func _on_match_state(p_state : NakamaRTAPI.MatchData): match p_state.op_code: 2: var data = JSON.parse_string(p_state.data) # Set player position given server bounds-checking if data["forcePlayerPos"]: player.set_position_data( Vector2( float(data["playerPos"]["x"]), float(data["playerPos"]["y"]) ), float(data["playerPos"]["radius_multiplier"]) ) if int(data["deathTimer"]) > 0: print("server says u died") %Player.kill() # Spawn new bullets for b in data["newBullets"]: var bullet = DanmakuBullet.new() bullet.setup_bullet( int(b["class"]), int(b["tick"]), b["x"], b["y"], b["radius_multiplier"] * Globals.SERVER_SIZE.x, b["vel_x"], b["vel_y"]) bullet.texture = load("res://test-bullet.png") bullet.position = bullet.get_current_pos(int(b["tick"])) # Reimplemented from ScalableSprite2D here atm var scale_ratio = ((b["radius_multiplier"] * 2) * Globals.SERVER_SIZE.x) / bullet.texture.get_width() bullet.scale = Vector2(scale_ratio, scale_ratio) add_child(bullet) bullets.append(bullet) predicted_tick = int(b["tick"]) delta_counter = 0 func attempt_auth() -> void: nakama_client = Nakama.create_client("defaultkey", "127.0.0.1", 7350, "http") nakama_session = await nakama_client.authenticate_device_async(OS.get_unique_id()) nakama_socket = Nakama.create_socket_from(nakama_client) var connected: NakamaAsyncResult = await nakama_socket.connect_async(nakama_session) if connected.is_exception(): print("An error occured when creating nakama socket: %s" % connected) return print("Oh baby we're ready.") func create_and_join_debug_match() -> void: var response: NakamaAPI.ApiRpc = await nakama_client.rpc_async(nakama_session, "manual_force_create_br_match_rpc") if response.is_exception(): print("An error occurred when calling manual_force_create_br_match_rpc: %s" % response) return var debug_br_match: NakamaRTAPI.Match = await nakama_socket.join_match_async(response.payload) if debug_br_match.is_exception(): print("An error occurred when joining debug BR match: %s" % response) return else: current_match_id = response.payload func predict_tick_and_broadcast(delta): delta_counter += delta # New tick (60 tick rate), broadcast player inputs var tick_time = 0.01666666666 if delta_counter >= tick_time: predicted_tick += 1 delta_counter -= tick_time var pos = get_node("../Player").position var json_string = JSON.stringify({"x": pos.x, "y": pos.y}) nakama_socket.send_match_state_async(current_match_id, 0, json_string) bullet_lerp_factor = delta_counter / tick_time func _on_child_exiting_tree(node: DanmakuBullet): bullets.erase(node)