Verbindung über ENet
NetLink verbindet Host und Gäste über ENet: Nachrichten des Kerns zuverlässig und in Reihenfolge, Positionen der Figuren unzuverlässig. Eine Verbindung schließt erst, wenn wartende Nachrichten draußen sind. SessionLink trägt die Nachrichten einer Sitzung über die Verbindung und reicht Positionen weiter. Die Tests verbinden zwei Seiten über die Loopback-Schnittstelle. Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,103 @@
|
||||
class_name SessionLink
|
||||
extends RefCounted
|
||||
## Carries the messages of a GwSession over a NetLink, and the positions of
|
||||
## the figures, which are not part of the shared world. Tells the game what
|
||||
## happened on the way.
|
||||
|
||||
## Bytes of a position: x and y as 32-bit floats.
|
||||
const POSITION_BYTES := 8
|
||||
|
||||
var session: GwSession
|
||||
var link: NetLink
|
||||
|
||||
|
||||
func _init(game_session: GwSession, net_link: NetLink) -> void:
|
||||
session = game_session
|
||||
link = net_link
|
||||
|
||||
|
||||
## Moves messages in both directions and returns notices, oldest first, as
|
||||
## dictionaries with a `type` entry:
|
||||
## - "guest_arrived" and "guest_left" (entry `peer`), at the host
|
||||
## - "world_received" (entry `resync`), "refused" (entry `reason`),
|
||||
## "protocol_error", "host_lost" and "failed", at a guest
|
||||
## - "divergence" (entries `peer`, `tick`, `hash`), at the host
|
||||
## - "figure" (entries `player`, `position`), everywhere
|
||||
## `delta` is the time since the last call.
|
||||
func pump(delta: float) -> Array[Dictionary]:
|
||||
var notices: Array[Dictionary] = []
|
||||
for event in link.poll(delta):
|
||||
match event["type"]:
|
||||
"connected":
|
||||
if session.is_host():
|
||||
session.connect_peer(event["peer"])
|
||||
notices.append({"type": "guest_arrived", "peer": event["peer"]})
|
||||
"disconnected":
|
||||
if session.is_host():
|
||||
session.disconnect_peer(event["peer"])
|
||||
notices.append({"type": "guest_left", "peer": event["peer"]})
|
||||
else:
|
||||
notices.append({"type": "host_lost"})
|
||||
"failed":
|
||||
notices.append({"type": "failed"})
|
||||
"message":
|
||||
notices.append_array(session.receive(event["peer"], event["bytes"]))
|
||||
"figure":
|
||||
_receive_figure(event["peer"], event["bytes"], notices)
|
||||
for divergence in session.take_divergences():
|
||||
divergence["type"] = "divergence"
|
||||
notices.append(divergence)
|
||||
flush()
|
||||
return notices
|
||||
|
||||
|
||||
## Sends what the session has for the network and closes the connections
|
||||
## the host gave up. A guest's messages wait until its host is reached.
|
||||
func flush() -> void:
|
||||
if not link.is_connected_to_peers():
|
||||
return
|
||||
for message in session.take_messages():
|
||||
link.send(message["peer"], message["bytes"])
|
||||
for peer in session.take_closing():
|
||||
link.close_peer(peer)
|
||||
|
||||
|
||||
## Tells the other machines where this machine's figure stands.
|
||||
func send_figure(position: Vector2) -> void:
|
||||
if session.is_host():
|
||||
var player := session.local_player()
|
||||
if player >= 0:
|
||||
link.send_figure(0, _figure_bytes(player, position))
|
||||
elif session.local_player() >= 0:
|
||||
link.send_figure(GwSession.HOST_PEER, _position_bytes(position))
|
||||
|
||||
|
||||
func _receive_figure(peer: int, bytes: PackedByteArray, notices: Array[Dictionary]) -> void:
|
||||
if session.is_host():
|
||||
# A guest sends only a position; the host knows whose it is and
|
||||
# passes it on to every other guest.
|
||||
var player := session.player_of_peer(peer)
|
||||
if player < 0 or bytes.size() != POSITION_BYTES:
|
||||
return
|
||||
var position := Vector2(bytes.decode_float(0), bytes.decode_float(4))
|
||||
notices.append({"type": "figure", "player": player, "position": position})
|
||||
link.send_figure(-peer, _figure_bytes(player, position))
|
||||
elif bytes.size() == 1 + POSITION_BYTES:
|
||||
var player := bytes.decode_u8(0)
|
||||
if player != session.local_player():
|
||||
var position := Vector2(bytes.decode_float(1), bytes.decode_float(5))
|
||||
notices.append({"type": "figure", "player": player, "position": position})
|
||||
|
||||
|
||||
func _position_bytes(position: Vector2) -> PackedByteArray:
|
||||
var bytes := PackedByteArray()
|
||||
bytes.resize(POSITION_BYTES)
|
||||
bytes.encode_float(0, position.x)
|
||||
bytes.encode_float(4, position.y)
|
||||
return bytes
|
||||
|
||||
|
||||
func _figure_bytes(player: int, position: Vector2) -> PackedByteArray:
|
||||
var bytes := PackedByteArray([player])
|
||||
bytes.append_array(_position_bytes(position))
|
||||
return bytes
|
||||
Reference in New Issue
Block a user