Defekte Sitzung gibt Mitspieler frei, nur echte Gäste beenden die Pause

Hält der Kern mit einem internen Fehler an, schließt ein Host seine Welt
für Gäste, und ein Gast kehrt ins Menü zurück, statt dass die anderen
ohne Nachricht warten. Eine Pause endet erst, wenn der Host einen Gast
angenommen hat, nicht schon bei einer bloßen Verbindung. So kann ein
Gast nicht mehr in einer pausierten Welt festhängen, wenn der Host
zwischen Verbindung und Gruß pausiert. Eine Pause lässt sich immer
beenden. Meldungen, die nach dem Ende einer Sitzung im selben Stapel
folgen, bleiben unbeachtet. Vier neue Tests decken das ab.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
Steven Wroblewski
2026-10-01 22:33:10 +02:00
parent 53ef02ae75
commit bfd237fd5c
2 changed files with 102 additions and 5 deletions
+33 -5
View File
@@ -57,6 +57,9 @@ var _save_blocked := false
var _figure_wait := 0.0
## The address a guest is joining, for messages.
var _joining := ""
## The host's accepted guests when _process last looked. A new one ends a
## pause.
var _known_guests := 0
func _ready() -> void:
@@ -233,12 +236,37 @@ func _leave(message: String) -> void:
_show_menu(message)
## A broken session runs no more ticks. Instead of leaving the others
## waiting, a host closes its world to guests and a guest leaves.
func _stop_sharing() -> void:
if not session.is_host():
_leave(tr("SIMULATION_STOPPED"))
return
link.link.close()
link = null
figures.clear()
_update_status()
## Ends a pause once the host accepted a guest: the guest joins in the next
## tick, and a paused world would keep it waiting. A connection that has not
## greeted yet is no guest.
func _end_pause_for_new_guests() -> void:
var guests := session.guest_count()
if guests > _known_guests and clock.paused:
_set_paused(false)
_known_guests = guests
func _process(delta: float) -> void:
if link != null:
for notice in link.pump(delta):
_on_notice(notice)
if session != null and session.is_broken() and link != null:
_stop_sharing()
if session == null or not session.is_running() or session.is_broken():
return
_end_pause_for_new_guests()
_update_marker()
if Input.is_action_pressed("dig") and not clock.paused:
_try_dig()
@@ -257,11 +285,10 @@ func _process(delta: float) -> void:
func _on_notice(notice: Dictionary) -> void:
# An earlier notice of the same batch may have ended the session.
if session == null:
return
match notice["type"]:
"guest_arrived":
# Pausing is for playing alone; a guest ends the pause.
if clock.paused:
_set_paused(false)
"world_received":
if notice["resync"]:
resyncs += 1
@@ -304,7 +331,8 @@ func _unhandled_input(event: InputEvent) -> void:
elif event.is_action_pressed("load_game"):
_reload()
elif event.is_action_pressed("toggle_pause"):
if session.is_host() and session.guest_count() == 0:
# Ending a pause is always allowed, starting one only alone.
if clock.paused or (session.is_host() and session.guest_count() == 0):
_set_paused(not clock.paused)
else:
hud.flash("PAUSE_ONLY_ALONE")