M1c: Gleichschritt im Netz #9
@@ -20,6 +20,9 @@ var connect_seconds := CONNECT_SECONDS
|
|||||||
|
|
||||||
var _peer: ENetMultiplayerPeer
|
var _peer: ENetMultiplayerPeer
|
||||||
var _peers: Dictionary[int, bool] = {}
|
var _peers: Dictionary[int, bool] = {}
|
||||||
|
## Connections that close_peer is closing. Nothing more goes to them: Godot
|
||||||
|
## reports an error for every packet to a connection in that state.
|
||||||
|
var _closing: Dictionary[int, bool] = {}
|
||||||
var _events: Array[Dictionary] = []
|
var _events: Array[Dictionary] = []
|
||||||
var _connecting := false
|
var _connecting := false
|
||||||
var _waited := 0.0
|
var _waited := 0.0
|
||||||
@@ -67,6 +70,7 @@ func _start() -> void:
|
|||||||
close()
|
close()
|
||||||
_peer = ENetMultiplayerPeer.new()
|
_peer = ENetMultiplayerPeer.new()
|
||||||
_peers.clear()
|
_peers.clear()
|
||||||
|
_closing.clear()
|
||||||
_peer.peer_connected.connect(_on_connected)
|
_peer.peer_connected.connect(_on_connected)
|
||||||
_peer.peer_disconnected.connect(_on_disconnected)
|
_peer.peer_disconnected.connect(_on_disconnected)
|
||||||
|
|
||||||
@@ -78,6 +82,7 @@ func _on_connected(peer: int) -> void:
|
|||||||
|
|
||||||
func _on_disconnected(peer: int) -> void:
|
func _on_disconnected(peer: int) -> void:
|
||||||
_peers.erase(peer)
|
_peers.erase(peer)
|
||||||
|
_closing.erase(peer)
|
||||||
_events.append({"type": "disconnected", "peer": peer})
|
_events.append({"type": "disconnected", "peer": peer})
|
||||||
|
|
||||||
|
|
||||||
@@ -118,7 +123,7 @@ func poll(delta: float) -> Array[Dictionary]:
|
|||||||
|
|
||||||
|
|
||||||
## Sends a message of the core to `peer`, reliably and in order. A message
|
## Sends a message of the core to `peer`, reliably and in order. A message
|
||||||
## to a connection that is gone is dropped.
|
## to a connection that is gone or being closed is dropped.
|
||||||
func send(peer: int, bytes: PackedByteArray) -> void:
|
func send(peer: int, bytes: PackedByteArray) -> void:
|
||||||
_put(peer, bytes, CHANNEL_CORE, MultiplayerPeer.TRANSFER_MODE_RELIABLE)
|
_put(peer, bytes, CHANNEL_CORE, MultiplayerPeer.TRANSFER_MODE_RELIABLE)
|
||||||
|
|
||||||
@@ -130,19 +135,34 @@ func send_figure(peer: int, bytes: PackedByteArray) -> void:
|
|||||||
|
|
||||||
|
|
||||||
func _put(peer: int, bytes: PackedByteArray, channel: int, mode: MultiplayerPeer.TransferMode) -> void:
|
func _put(peer: int, bytes: PackedByteArray, channel: int, mode: MultiplayerPeer.TransferMode) -> void:
|
||||||
if not is_connected_to_peers() or _peers.is_empty():
|
if not is_connected_to_peers():
|
||||||
return
|
return
|
||||||
if peer > 0 and not _peers.has(peer):
|
|
||||||
return
|
|
||||||
_peer.set_target_peer(peer)
|
|
||||||
_peer.set_transfer_channel(channel)
|
_peer.set_transfer_channel(channel)
|
||||||
_peer.set_transfer_mode(mode)
|
_peer.set_transfer_mode(mode)
|
||||||
|
# One packet per connection, so that no packet goes to a connection that
|
||||||
|
# is gone or being closed; Godot's own sending to all would.
|
||||||
|
for target in _targets(peer):
|
||||||
|
_peer.set_target_peer(target)
|
||||||
_peer.put_packet(bytes)
|
_peer.put_packet(bytes)
|
||||||
|
|
||||||
|
|
||||||
|
## The connections a packet for `peer` goes to: that one, every one if
|
||||||
|
## `peer` is 0, or every one but -`peer` if `peer` is negative. Connections
|
||||||
|
## that are being closed get nothing.
|
||||||
|
func _targets(peer: int) -> Array[int]:
|
||||||
|
var targets: Array[int] = []
|
||||||
|
for open: int in _peers:
|
||||||
|
if _closing.has(open):
|
||||||
|
continue
|
||||||
|
if peer == 0 or open == peer or (peer < 0 and open != -peer):
|
||||||
|
targets.append(open)
|
||||||
|
return targets
|
||||||
|
|
||||||
|
|
||||||
## Closes the connection to `peer` once the messages waiting for it are out.
|
## Closes the connection to `peer` once the messages waiting for it are out.
|
||||||
func close_peer(peer: int) -> void:
|
func close_peer(peer: int) -> void:
|
||||||
if _peers.has(peer):
|
if _peers.has(peer) and not _closing.has(peer):
|
||||||
|
_closing[peer] = true
|
||||||
_peer.get_peer(peer).peer_disconnect_later()
|
_peer.get_peer(peer).peer_disconnect_later()
|
||||||
|
|
||||||
|
|
||||||
@@ -151,4 +171,5 @@ func close() -> void:
|
|||||||
if is_open():
|
if is_open():
|
||||||
_peer.close()
|
_peer.close()
|
||||||
_peers.clear()
|
_peers.clear()
|
||||||
|
_closing.clear()
|
||||||
_connecting = false
|
_connecting = false
|
||||||
|
|||||||
@@ -100,14 +100,43 @@ func test_a_guest_that_quits_is_seen_leaving() -> void:
|
|||||||
host.close()
|
host.close()
|
||||||
|
|
||||||
|
|
||||||
func test_messages_to_a_connection_that_is_gone_are_dropped() -> void:
|
## Godot reports an error for every packet to a connection that is gone or
|
||||||
|
## being closed; the test runner turns each such error into a failure.
|
||||||
|
func test_nothing_is_sent_to_connections_that_are_gone_or_closing() -> void:
|
||||||
var host := NetLink.new()
|
var host := NetLink.new()
|
||||||
check_eq(host.host(0, "127.0.0.1"), OK, "the host listens")
|
check_eq(host.host(0, "127.0.0.1"), OK, "the host listens")
|
||||||
|
var first := NetLink.new()
|
||||||
|
var second := NetLink.new()
|
||||||
|
first.join("127.0.0.1", host.local_port())
|
||||||
|
second.join("127.0.0.1", host.local_port())
|
||||||
|
await _pump([host, first, second], 10)
|
||||||
|
var peers: Array = _events[host].map(func(event: Dictionary) -> int: return event["peer"])
|
||||||
|
check_eq(peers.size(), 2, "two guests connected")
|
||||||
|
var leaving: int = peers[0]
|
||||||
|
var staying: int = peers[1]
|
||||||
|
|
||||||
|
# Connections that never existed.
|
||||||
host.send(12345, PackedByteArray([1]))
|
host.send(12345, PackedByteArray([1]))
|
||||||
host.send_figure(12345, PackedByteArray([1]))
|
host.send_figure(12345, PackedByteArray([1]))
|
||||||
|
host.send_figure(-12345, PackedByteArray([1]))
|
||||||
host.close_peer(12345)
|
host.close_peer(12345)
|
||||||
check_eq(host.poll(0.0), [], "nothing happened")
|
# A connection that is being closed, and everybody while it closes.
|
||||||
host.close()
|
host.close_peer(leaving)
|
||||||
|
for frame in 10:
|
||||||
|
host.send(leaving, PackedByteArray([2]))
|
||||||
|
host.send_figure(leaving, PackedByteArray([2]))
|
||||||
|
host.send_figure(-staying, PackedByteArray([2]))
|
||||||
|
host.send_figure(0, PackedByteArray([2]))
|
||||||
|
await _pump([host, first, second], 1)
|
||||||
|
# The connection is gone now.
|
||||||
|
host.send(leaving, PackedByteArray([3]))
|
||||||
|
host.send_figure(-leaving, PackedByteArray([3]))
|
||||||
|
await _pump([host, first, second], 5)
|
||||||
|
|
||||||
|
check(_types(first).has("disconnected"), "the first guest was closed")
|
||||||
|
check(not _types(second).has("disconnected"), "the second guest stays")
|
||||||
|
for link in [host, first, second]:
|
||||||
|
link.close()
|
||||||
|
|
||||||
|
|
||||||
func test_a_guest_gives_up_when_nobody_answers() -> void:
|
func test_a_guest_gives_up_when_nobody_answers() -> void:
|
||||||
|
|||||||
Reference in New Issue
Block a user