Enhance character deletion process in EventsWorker and UserCharacterWorker: Added SQL queries to delete associated data such as knowledge, debtors prism, political offices, and election candidates upon character deletion. Implemented event publishing for character death and status updates after inheritance changes, improving event handling and UI responsiveness.
All checks were successful
Deploy yourpart (blue-green) / deploy (push) Successful in 1m41s
All checks were successful
Deploy yourpart (blue-green) / deploy (push) Successful in 1m41s
This commit is contained in:
110
docs/FALUKANT_DEATH_SUCCESSION_SMOKE_TEST.md
Normal file
110
docs/FALUKANT_DEATH_SUCCESSION_SMOKE_TEST.md
Normal file
@@ -0,0 +1,110 @@
|
||||
# Falukant Smoke-Test: Tod -> Erbwechsel -> UI-Status
|
||||
|
||||
Dieser Smoke-Test validiert den kritischen Ablauf:
|
||||
|
||||
- Spieler-Charakter stirbt
|
||||
- Erbe wird gesetzt
|
||||
- alte charakterbezogene Daten sind bereinigt
|
||||
- UI bekommt verlässlich den Status-Refresh
|
||||
|
||||
## Ziel
|
||||
|
||||
Verhindern, dass nach Tod/Erbe ein Mischzustand entsteht
|
||||
(z. B. Erben-Bild, aber alte Statusdaten des verstorbenen Charakters).
|
||||
|
||||
## Voraussetzungen
|
||||
|
||||
- Daemon läuft mit aktuellen Änderungen.
|
||||
- Zugriff auf DB (psql).
|
||||
- Zugriff auf WebSocket-Eventstream oder Daemon-Log.
|
||||
- Ein Test-User mit:
|
||||
- aktivem Spieler-Charakter (`user_id` gesetzt),
|
||||
- mindestens einem potenziellen Erben in `child_relation`.
|
||||
|
||||
## Testfall A: Tod über `UserCharacterWorker` (health <= 0)
|
||||
|
||||
1. Testkandidaten wählen:
|
||||
|
||||
```sql
|
||||
SELECT c.id AS character_id, c.user_id
|
||||
FROM falukant_data.character c
|
||||
WHERE c.user_id IS NOT NULL
|
||||
ORDER BY c.updated_at DESC
|
||||
LIMIT 20;
|
||||
```
|
||||
|
||||
2. Einen Charakter künstlich auf `health = 0` setzen:
|
||||
|
||||
```sql
|
||||
UPDATE falukant_data.character
|
||||
SET health = 0, updated_at = NOW()
|
||||
WHERE id = <CHARACTER_ID>;
|
||||
```
|
||||
|
||||
3. Worker laufen lassen (Death-Check oder nächster Verarbeitungstakt).
|
||||
|
||||
4. WebSocket/Log prüfen, erwartet:
|
||||
- `CharacterDeath` mit altem `character_id`
|
||||
- `falukantUpdateStatus` mit `user_id` des betroffenen Spielers
|
||||
|
||||
5. DB prüfen, erwartet:
|
||||
|
||||
```sql
|
||||
-- alter Charakter weg
|
||||
SELECT 1
|
||||
FROM falukant_data.character
|
||||
WHERE id = <CHARACTER_ID>;
|
||||
|
||||
-- Spieler zeigt auf Erben
|
||||
SELECT c.id, c.user_id
|
||||
FROM falukant_data.character c
|
||||
WHERE c.user_id = <USER_ID>;
|
||||
```
|
||||
|
||||
```sql
|
||||
-- Todes-Cleanup (sollte leer sein)
|
||||
SELECT COUNT(*) FROM falukant_data.knowledge WHERE character_id = <CHARACTER_ID>;
|
||||
SELECT COUNT(*) FROM falukant_data.debtors_prism WHERE character_id = <CHARACTER_ID>;
|
||||
SELECT COUNT(*) FROM falukant_data.political_office WHERE character_id = <CHARACTER_ID>;
|
||||
SELECT COUNT(*) FROM falukant_data.election_candidate WHERE character_id = <CHARACTER_ID>;
|
||||
```
|
||||
|
||||
```sql
|
||||
-- politische Ämter historisiert (falls vorher vorhanden)
|
||||
SELECT *
|
||||
FROM falukant_log.political_office_history
|
||||
WHERE character_id = <CHARACTER_ID>
|
||||
ORDER BY end_date DESC
|
||||
LIMIT 5;
|
||||
```
|
||||
|
||||
Passkriterium:
|
||||
- alter Charakter gelöscht,
|
||||
- Nachfolger gesetzt,
|
||||
- Cleanup-Counts = 0,
|
||||
- `falukantUpdateStatus` gesendet.
|
||||
|
||||
## Testfall B: Tod über `EventsWorker`
|
||||
|
||||
Der gleiche Prüfsatz wie in Testfall A, aber mit Tod aus Event-Pfad.
|
||||
|
||||
Hinweis:
|
||||
- Falls kein reproduzierbares Zufallsereignis vorliegt, kann derselbe technische Endzustand
|
||||
pragmatisch über A validiert werden.
|
||||
- Zusätzlicher Fokus hier: auch im Event-Pfad müssen Cleanup + Status-Refresh identisch sein.
|
||||
|
||||
## UI-Schnellcheck
|
||||
|
||||
Nach Eintreffen von `falukantUpdateStatus`:
|
||||
|
||||
- Avatar/Bild entspricht dem Erben.
|
||||
- Statusdaten (Familie/Politik/bezogene Anzeigen) zeigen keine Relikte des Verstorbenen.
|
||||
- Kein inkonsistenter Mischzustand nach manuellem Reload.
|
||||
|
||||
## Regression-Checkliste
|
||||
|
||||
- [ ] `CharacterDeath` kommt genau für den verstorbenen Charakter.
|
||||
- [ ] `falukantUpdateStatus` kommt nach Erbwechsel für den betroffenen User.
|
||||
- [ ] `knowledge`/`debtors_prism`/`political_office`/`election_candidate` sind bereinigt.
|
||||
- [ ] `political_office_history` enthält entfernte Ämter (falls vorhanden).
|
||||
- [ ] UI bleibt konsistent (Bild + Status gehören zum selben Charakter).
|
||||
@@ -46,7 +46,11 @@ use crate::worker::sql::{
|
||||
QUERY_GET_USER_ID,
|
||||
QUERY_DELETE_CHILD_RELATION,
|
||||
QUERY_DELETE_CHILD_RELATION_BY_PARENT,
|
||||
QUERY_DELETE_DEBTORS_PRISM,
|
||||
QUERY_DELETE_CHARACTER,
|
||||
QUERY_DELETE_ELECTION_CANDIDATE,
|
||||
QUERY_DELETE_KNOWLEDGE,
|
||||
QUERY_DELETE_POLITICAL_OFFICE,
|
||||
QUERY_GET_HEIR,
|
||||
QUERY_SET_CHARACTER_USER,
|
||||
QUERY_GET_CURRENT_MONEY,
|
||||
@@ -1815,6 +1819,12 @@ impl EventsWorker {
|
||||
broker: &MessageBroker,
|
||||
character_id: i32,
|
||||
) -> Result<(), DbError> {
|
||||
let death_event = format!(
|
||||
r#"{{"event":"CharacterDeath","character_id":{}}}"#,
|
||||
character_id
|
||||
);
|
||||
broker.publish(death_event);
|
||||
|
||||
// Diese Funktion verwendet die gleiche Logik wie CharacterCreationWorker
|
||||
// Wir müssen die Queries aus character_creation.rs verwenden
|
||||
let mut conn = pool
|
||||
@@ -1922,7 +1932,17 @@ impl EventsWorker {
|
||||
}
|
||||
}
|
||||
|
||||
// 5) Charakter löschen
|
||||
// 5) Weitere charaktergebundene Daten löschen (wie UserCharacterWorker)
|
||||
conn.prepare("delete_knowledge", QUERY_DELETE_KNOWLEDGE)?;
|
||||
conn.prepare("delete_debtors_prism", QUERY_DELETE_DEBTORS_PRISM)?;
|
||||
conn.prepare("delete_political_office", QUERY_DELETE_POLITICAL_OFFICE)?;
|
||||
conn.prepare("delete_election_candidate", QUERY_DELETE_ELECTION_CANDIDATE)?;
|
||||
conn.execute("delete_knowledge", &[&character_id])?;
|
||||
conn.execute("delete_debtors_prism", &[&character_id])?;
|
||||
conn.execute("delete_political_office", &[&character_id])?;
|
||||
conn.execute("delete_election_candidate", &[&character_id])?;
|
||||
|
||||
// 6) Charakter löschen
|
||||
conn.prepare("delete_character", QUERY_DELETE_CHARACTER)?;
|
||||
conn.execute("delete_character", &[&character_id])?;
|
||||
|
||||
@@ -2040,6 +2060,13 @@ impl EventsWorker {
|
||||
&format!("Erbe für Charakter {}", deceased_character_id),
|
||||
)?;
|
||||
|
||||
// Expliziter Status-Refresh für die UI nach Erbwechsel.
|
||||
let status = format!(
|
||||
r#"{{"event":"falukantUpdateStatus","user_id":{}}}"#,
|
||||
falukant_user_id
|
||||
);
|
||||
broker.publish(status);
|
||||
|
||||
eprintln!(
|
||||
"[EventsWorker] Erbe {} übernimmt Vermögen von Charakter {} (User {}): {:.2} (von {:.2} Gesamtvermögen, {} weitere Kinder)",
|
||||
heir_id, deceased_character_id, falukant_user_id, final_money, total_assets, child_count
|
||||
|
||||
@@ -960,6 +960,13 @@ impl UserCharacterWorker {
|
||||
}
|
||||
self.set_new_money(falukant_user_id, new_money)?;
|
||||
|
||||
// Nach Erbwechsel den Status sicher neu laden lassen.
|
||||
let update_status = format!(
|
||||
r#"{{"event":"falukantUpdateStatus","user_id":{}}}"#,
|
||||
falukant_user_id
|
||||
);
|
||||
self.base.broker.publish(update_status);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user