parent
8338716de0
commit
b6f62633e6
3 changed files with 205 additions and 169 deletions
@ -0,0 +1,161 @@ |
||||
using Godot; |
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.Linq; |
||||
|
||||
public class Network : Node |
||||
{ |
||||
public enum Status |
||||
{ |
||||
NoConnection, |
||||
ServerRunning, |
||||
Connecting, |
||||
ConnectedToServer, |
||||
} |
||||
|
||||
[Export] public ushort DefaultPort { get; set; } = 42005; |
||||
[Export] public string DefaultAddress { get; set; } = "localhost"; |
||||
|
||||
public Node PlayerContainer { get; private set; } |
||||
public Player OwnPlayer { get; private set; } |
||||
public PackedScene OtherPlayer { get; private set; } |
||||
|
||||
public Status CurrentStatus { get; private set; } = Status.NoConnection; |
||||
[Signal] public delegate void StatusChanged(Status status); |
||||
|
||||
public override void _Ready() |
||||
{ |
||||
OtherPlayer = GD.Load<PackedScene>("res://scene/OtherPlayer.tscn"); |
||||
PlayerContainer = GetParent(); |
||||
|
||||
GetTree().Connect("connected_to_server", this, "OnClientConnected"); |
||||
GetTree().Connect("connection_failed", this, "DisconnectFromServer"); |
||||
GetTree().Connect("server_disconnected", this, "DisconnectFromServer"); |
||||
|
||||
GetTree().Connect("network_peer_connected", this, "OnPeerConnected"); |
||||
GetTree().Connect("network_peer_disconnected", this, "OnPeerDisconnected"); |
||||
} |
||||
|
||||
public override void _Process(float delta) |
||||
{ |
||||
if (OwnPlayer == null) return; |
||||
RpcUnreliable("OnPlayerMoved", OwnPlayer.Position); |
||||
} |
||||
|
||||
|
||||
public Error StartServer(ushort port) |
||||
{ |
||||
if (GetTree().NetworkPeer != null) throw new InvalidOperationException(); |
||||
|
||||
var peer = new NetworkedMultiplayerENet(); |
||||
// TODO: Somehow show there was an error. |
||||
var error = peer.CreateServer(port); |
||||
if (error != Error.Ok) return error; |
||||
GetTree().NetworkPeer = peer; |
||||
OwnPlayer = FindOwnPlayer(); |
||||
|
||||
CurrentStatus = Status.ServerRunning; |
||||
EmitSignal(nameof(StatusChanged), CurrentStatus); |
||||
|
||||
return Error.Ok; |
||||
} |
||||
|
||||
public void StopServer() |
||||
{ |
||||
if ((GetTree().NetworkPeer == null) || !GetTree().IsNetworkServer()) throw new InvalidOperationException(); |
||||
|
||||
// TODO: Disconnect players gracefully. |
||||
((NetworkedMultiplayerENet)GetTree().NetworkPeer).CloseConnection(); |
||||
GetTree().NetworkPeer = null; |
||||
|
||||
OwnPlayer = null; |
||||
foreach (var player in GetOtherPlayers()) |
||||
player.RemoveFromParent(); |
||||
|
||||
CurrentStatus = Status.NoConnection; |
||||
EmitSignal(nameof(StatusChanged), CurrentStatus); |
||||
} |
||||
|
||||
public Error ConnectToServer(string address, ushort port) |
||||
{ |
||||
if (GetTree().NetworkPeer != null) throw new InvalidOperationException(); |
||||
|
||||
var peer = new NetworkedMultiplayerENet(); |
||||
// TODO: Somehow show there was an error. |
||||
var error = peer.CreateClient(address, port); |
||||
if (error != Error.Ok) return error; |
||||
GetTree().NetworkPeer = peer; |
||||
|
||||
CurrentStatus = Status.Connecting; |
||||
EmitSignal(nameof(StatusChanged), CurrentStatus); |
||||
|
||||
return Error.Ok; |
||||
} |
||||
|
||||
public void DisconnectFromServer() |
||||
{ |
||||
if ((GetTree().NetworkPeer == null) || GetTree().IsNetworkServer()) throw new InvalidOperationException(); |
||||
|
||||
// TODO: Disconnect from server gracefully. |
||||
((NetworkedMultiplayerENet)GetTree().NetworkPeer).CloseConnection(); |
||||
GetTree().NetworkPeer = null; |
||||
|
||||
OwnPlayer = null; |
||||
foreach (var player in GetOtherPlayers()) |
||||
player.RemoveFromParent(); |
||||
|
||||
CurrentStatus = Status.NoConnection; |
||||
EmitSignal(nameof(StatusChanged), CurrentStatus); |
||||
} |
||||
|
||||
private Player FindOwnPlayer() |
||||
=> GetTree().Root.GetChild(0).GetChildren().OfType<Player>().First(); |
||||
|
||||
private Node2D GetPlayerWithId(int id) |
||||
=> PlayerContainer.GetNodeOrNull<Node2D>(id.ToString()); |
||||
private Node2D GetOrCreatePlayerWithId(int id) |
||||
{ |
||||
var player = GetPlayerWithId(id); |
||||
if (player == null) { |
||||
player = (Node2D)OtherPlayer.Instance(); |
||||
// TODO: Use "set_network_master". |
||||
player.Name = id.ToString(); |
||||
PlayerContainer.AddChild(player); |
||||
} |
||||
return player; |
||||
} |
||||
|
||||
// TODO: This assumes that any node whose name starts with a digit is a player. |
||||
private IEnumerable<Node2D> GetOtherPlayers() |
||||
=> PlayerContainer.GetChildren().OfType<Node2D>() |
||||
.Where(node => char.IsDigit(node.Name[0])); |
||||
|
||||
|
||||
#pragma warning disable IDE0051 |
||||
|
||||
private void OnClientConnected() |
||||
{ |
||||
OwnPlayer = FindOwnPlayer(); |
||||
|
||||
CurrentStatus = Status.ConnectedToServer; |
||||
EmitSignal(nameof(StatusChanged), CurrentStatus); |
||||
} |
||||
|
||||
|
||||
private void OnPeerConnected(int id) |
||||
{ |
||||
|
||||
} |
||||
|
||||
private void OnPeerDisconnected(int id) |
||||
=> GetPlayerWithId(id)?.RemoveFromParent(); |
||||
|
||||
|
||||
[Remote] |
||||
private void OnPlayerMoved(Vector2 position) |
||||
{ |
||||
var id = GetTree().GetRpcSenderId(); |
||||
var player = GetOrCreatePlayerWithId(id); |
||||
player.Position = position; |
||||
} |
||||
} |
Loading…
Reference in new issue