using Godot; namespace AceField.Scripts.Logic; public partial class World : Node2D { [Export] public Scoreboard Scoreboard; [Export] public PackedScene PlayerScene; [Export] public int RoundCount = 1; [Export] public int RoundTotalCount = 20; [Export] public double RoundDuration = 60; [Export] public double RoundProgress; [Export] public double RoundTimeLeft; private Timer _roundTimer; public void StartGame(string currentPlayerName = null) { if (!Multiplayer.IsServer()) return; _roundTimer = new Timer(); _roundTimer.WaitTime = RoundDuration; _roundTimer.Autostart = true; _roundTimer.Timeout += NewRound; _roundTimer.OneShot = true; AddChild(_roundTimer); _roundTimer.Start(); // Add players into the game PutPlayers(currentPlayerName); } public override void _Ready() { if (!Multiplayer.IsServer()) return; // Handling player connect / disconnect after this client connected Multiplayer.PeerDisconnected += RemovePlayer_Adaptor; Multiplayer.PeerConnected += AddPlayer_Adaptor; // Handling player connected before this client foreach (var id in Multiplayer.GetPeers()) Scoreboard.AddPlayer(id); // Add this client as a player if client isn't a dedicated server if (!OS.HasFeature("dedicated_server")) Scoreboard.AddPlayer(1); } public override void _ExitTree() { if (!Multiplayer.IsServer()) return; Multiplayer.PeerDisconnected -= RemovePlayer_Adaptor; Multiplayer.PeerConnected -= AddPlayer_Adaptor; } public override void _Process(double delta) { if (Multiplayer.IsServer()) { RoundProgress = _roundTimer.TimeLeft / _roundTimer.WaitTime; RoundTimeLeft = _roundTimer.TimeLeft; } } private static string BuildPlayerName(int id) => $"Player@{id}"; private void AddPlayer_Adaptor(long id) => Scoreboard.AddPlayer((int)id); private void RemovePlayer_Adaptor(long id) => Scoreboard.RemovePlayer((int)id); private void SpawnPlayer(int id, string name = null) { var player = PlayerScene.Instantiate(); player.PlayerId = id; var position = Vector2.FromAngle(GD.Randf() * 2 * Mathf.Pi); player.Position = new Vector2(position.X * 5f * GD.Randf(), position.Y * 5f * GD.Randf()); player.Name = BuildPlayerName(id); player.PlayerDied += (killerId) => { if (killerId == 0) return; Scoreboard.AddScore(killerId); }; AddChild(player, true); player.PlayerName = name; } private void PutPlayers(string currentPlayerName = null) { // Spawn clients foreach (var id in Multiplayer.GetPeers()) SpawnPlayer(id, Scoreboard.Players[id]?.Name); // Spawn host if (!OS.HasFeature("dedicated_server")) SpawnPlayer(1, currentPlayerName ?? Scoreboard.Players[1]?.Name); } private void NewRound() { if (RoundCount >= RoundTotalCount) { // TODO End this game return; } RoundCount++; foreach (var child in GetChildren()) { if (child is not Timer) child.QueueFree(); } PutPlayers(); _roundTimer.Start(); } public Player GetCurrentPlayer() { foreach (var child in GetChildren()) { if (child is Player { IsCurrentPlayer: true } player) { return player; } } return null; } public T GetTileByPosition(Vector2 position) where T : Node2D { foreach (var item in GetChildren()) { if (item is T tile && tile.Position == position) return tile; } return null; } }