Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
d10054477f
|
|||
| 74ab464497 | |||
|
a4a7bb265d
|
|||
| 572ca5c2b2 |
@@ -1727,6 +1727,7 @@ def _hc_merge_character_rows(rows):
|
||||
merged["total_enemies_killed"] = total_kills
|
||||
merged["alive"] = alive
|
||||
merged["dead_at"] = dead_at
|
||||
_hc_apply_canonical_death_overlay(merged)
|
||||
merged["last_seen_at"] = last_seen_at or None
|
||||
merged["updated_at"] = updated_at or None
|
||||
|
||||
@@ -1734,6 +1735,79 @@ def _hc_merge_character_rows(rows):
|
||||
|
||||
return combined
|
||||
|
||||
|
||||
def _hc_death_overlay_int(value):
|
||||
try:
|
||||
if value is None or value == "":
|
||||
return None
|
||||
return int(value)
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
|
||||
def _hc_canonical_accounts_root():
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
return Path(os.environ.get(
|
||||
"PSOPEEPS_HC_CANONICAL_ACCOUNTS_ROOT",
|
||||
"/home/rbatty/.local/share/psopeeps_account_sync/canonical/accounts",
|
||||
))
|
||||
|
||||
|
||||
def _hc_canonical_slot_is_dead(guild_card, character_slot):
|
||||
import json
|
||||
|
||||
account_id = _hc_death_overlay_int(guild_card)
|
||||
slot = _hc_death_overlay_int(character_slot)
|
||||
if account_id is None or slot is None:
|
||||
return False
|
||||
|
||||
players_dir = _hc_canonical_accounts_root() / f"{account_id:010d}" / "system" / "players"
|
||||
if not players_dir.exists():
|
||||
return False
|
||||
|
||||
if any(players_dir.glob(f"player_*_{slot}.psochar.hardcore-dead")):
|
||||
return True
|
||||
|
||||
deaths_log = players_dir / "hardcore-deaths.jsonl"
|
||||
if not deaths_log.exists():
|
||||
return False
|
||||
|
||||
suffix = f"_{slot}.psochar"
|
||||
try:
|
||||
lines = deaths_log.read_text(errors="replace").splitlines()
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
for line in lines:
|
||||
line = line.strip()
|
||||
if not line:
|
||||
continue
|
||||
try:
|
||||
entry = json.loads(line)
|
||||
except Exception:
|
||||
continue
|
||||
|
||||
if _hc_death_overlay_int(entry.get("account_id")) != account_id:
|
||||
continue
|
||||
|
||||
if str(entry.get("character_file") or "").endswith(suffix):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def _hc_apply_canonical_death_overlay(row):
|
||||
if _hc_canonical_slot_is_dead(
|
||||
row.get("guild_card") or row.get("account_id"),
|
||||
row.get("character_slot"),
|
||||
):
|
||||
row["alive"] = False
|
||||
row.setdefault("dead_at", "canonical-hardcore-dead")
|
||||
return row
|
||||
|
||||
|
||||
def _hc_combined_payload():
|
||||
source_rows, errors = _hc_get_source_characters()
|
||||
combined = _hc_merge_character_rows(source_rows)
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet">
|
||||
<link rel="stylesheet" href="style.css?v=leaderboard-table-restore-20260610-1">
|
||||
<link rel="stylesheet" href="style.css?v=leaderboard-level-column-20260613-1">
|
||||
<script src="app.js?v=saves-synced-20260609-2" defer></script>
|
||||
</head>
|
||||
<body>
|
||||
@@ -83,6 +83,6 @@
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
<script src="placeholder-pages.js?v=hardcore-leaderboard-table-restore-20260610-1" defer></script>
|
||||
<script src="placeholder-pages.js?v=hardcore-leaderboard-level-column-20260613-1" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
{ key: "rank", label: "Rank", numeric: true },
|
||||
{ key: "name", label: "Player Name" },
|
||||
{ key: "points", label: "Points", numeric: true },
|
||||
{ key: "level", label: "Level", numeric: true },
|
||||
{ key: "status", label: "Status" },
|
||||
{ key: "class", label: "Class" },
|
||||
{ key: "secid", label: "SecID" },
|
||||
@@ -61,6 +62,7 @@
|
||||
originalRank: index + 1,
|
||||
name: row.PlayerName || row.CharacterName || row.character_name || "",
|
||||
points: Number(row.Points ?? row.TotalPoints ?? 0),
|
||||
level: Number(row.Level ?? row.level ?? 0),
|
||||
class: row.Class || row.character_class || "",
|
||||
secid: row.SecID || row.section_id || "",
|
||||
kills: Number(row.Kills ?? row.TotalKills ?? row.total_enemies_killed ?? 0),
|
||||
@@ -168,6 +170,7 @@
|
||||
<td data-label="Rank">${rank}</td>
|
||||
<td data-label="Player Name">${escapeHtml(row.name)}</td>
|
||||
<td data-label="Points">${fmtNumber(row.points)}</td>
|
||||
<td data-label="Level">${fmtNumber(row.level)}</td>
|
||||
<td data-label="Status">${escapeHtml(row.status)}</td>
|
||||
<td data-label="Class">${escapeHtml(row.class || "—")}</td>
|
||||
<td data-label="SecID">${escapeHtml(row.secid || "—")}</td>
|
||||
@@ -180,7 +183,7 @@
|
||||
<div class="leaderboard-table-wrap">
|
||||
<table class="leaderboard-table">
|
||||
<thead><tr>${head}</tr></thead>
|
||||
<tbody>${body || `<tr><td colspan="8">No Hardcore leaderboard rows yet.</td></tr>`}</tbody>
|
||||
<tbody>${body || `<tr><td colspan="9">No Hardcore leaderboard rows yet.</td></tr>`}</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="leaderboard-pager">
|
||||
|
||||
+4
-2
@@ -2084,8 +2084,9 @@ button.inline-link,
|
||||
|
||||
.leaderboard-table td:nth-child(1),
|
||||
.leaderboard-table td:nth-child(3),
|
||||
.leaderboard-table td:nth-child(6),
|
||||
.leaderboard-table td:nth-child(7) {
|
||||
.leaderboard-table td:nth-child(4),
|
||||
.leaderboard-table td:nth-child(7),
|
||||
.leaderboard-table td:nth-child(8) {
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
|
||||
@@ -2153,6 +2154,7 @@ button.inline-link,
|
||||
|
||||
.leaderboard-table td:nth-child(1),
|
||||
.leaderboard-table td:nth-child(3),
|
||||
.leaderboard-table td:nth-child(4),
|
||||
.leaderboard-table td:nth-child(7),
|
||||
.leaderboard-table td:nth-child(8) {
|
||||
font-variant-numeric: tabular-nums;
|
||||
|
||||
Reference in New Issue
Block a user