Power-series: bind history to account id, not name
Browse filesThe live lookup only populates player_id when ranks are attached
(_sm_attach_level_ranks), which normal lookups skip — so recorded
points were key'd by name (or dropped), and the chart (which queries
by id) found nothing. Now the recorder resolves the account id from
the scanner-maintained leaderboard by name when the result lacks a
player_id, and stores strictly under id:<player_id> (no name fallback),
so history survives renames and never fragments by name. Harden the
name->id leaderboard scan against concurrent-mutation RuntimeErrors.
Verified end-to-end: a normal lookup (player_id=None) and a scanner
ingest push both now record an exact point under the account id;
sub-1-Qnt accounts are still skipped.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
@@ -8320,8 +8320,12 @@ def _sm_power_series_record(result: dict):
|
|
| 8320 |
level = int(result.get("level"))
|
| 8321 |
except (TypeError, ValueError):
|
| 8322 |
return
|
| 8323 |
-
|
| 8324 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 8325 |
return
|
| 8326 |
gold = _sm_float_sort_value(result.get("gold_raw"))
|
| 8327 |
sword = _sm_pseries_gear_type(result.get("sword_type"))
|
|
@@ -8372,9 +8376,16 @@ def _sm_pseries_resolve_key(username: str, player_id: str):
|
|
| 8372 |
try:
|
| 8373 |
with _SM_LEADERBOARD_LOCK:
|
| 8374 |
players = _sm_leaderboard_load_unlocked().get("players") or {}
|
| 8375 |
-
|
| 8376 |
-
|
| 8377 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 8378 |
except Exception: # noqa: BLE001
|
| 8379 |
pass
|
| 8380 |
return key
|
|
|
|
| 8320 |
level = int(result.get("level"))
|
| 8321 |
except (TypeError, ValueError):
|
| 8322 |
return
|
| 8323 |
+
# Zeitreihe NUR an die Account-ID binden (kein name:-Fallback) -> überlebt Umbenennungen
|
| 8324 |
+
# und wird nie nach Namen fragmentiert. player_id direkt bevorzugt; fehlt sie (normaler
|
| 8325 |
+
# Lookup ohne Rang -> _sm_attach_level_ranks setzt sie nicht), wird sie über das
|
| 8326 |
+
# (scanner-gepflegte) Leaderboard per Name aufgelöst. Keine ID auflösbar -> nicht speichern.
|
| 8327 |
+
key = _sm_pseries_resolve_key(result.get("username") or "", result.get("player_id") or "")
|
| 8328 |
+
if not key.startswith("id:"):
|
| 8329 |
return
|
| 8330 |
gold = _sm_float_sort_value(result.get("gold_raw"))
|
| 8331 |
sword = _sm_pseries_gear_type(result.get("sword_type"))
|
|
|
|
| 8376 |
try:
|
| 8377 |
with _SM_LEADERBOARD_LOCK:
|
| 8378 |
players = _sm_leaderboard_load_unlocked().get("players") or {}
|
| 8379 |
+
# Lock-frei iterieren (kein langer Lock-Hold bei ~1,7 Mio Zeilen). Falls ein anderer
|
| 8380 |
+
# Thread die dict-Groesse waehrend der Iteration aendert -> kurz erneut versuchen.
|
| 8381 |
+
for _attempt in range(3):
|
| 8382 |
+
try:
|
| 8383 |
+
for k, r in players.items():
|
| 8384 |
+
if str(k).startswith("id:") and _discord_lookup_key((r or {}).get("username")) == want:
|
| 8385 |
+
return str(k)
|
| 8386 |
+
break
|
| 8387 |
+
except RuntimeError:
|
| 8388 |
+
continue
|
| 8389 |
except Exception: # noqa: BLE001
|
| 8390 |
pass
|
| 8391 |
return key
|