18 KiB
OGame Galaxy Viewer — Documentazione tecnica
Visualizzatore di galassie per OGame (s170-ar, universo "Rosalind") con archivio personale dei rapporti di spionaggio e classifiche filtrate.
Questa documentazione descrive l'architettura, i sorgenti e, per ciascuno, funzioni e metodi.
1. Panoramica
Il progetto è una web app personale composta da:
| Componente | Tecnologia | Ruolo |
|---|---|---|
| Backend | Python 3 + Flask | API REST, aggiornamento dati, archivio rapporti |
| Frontend | HTML/CSS/JS vanilla | Galaxy view, dettagli rapporti, classifiche |
| Dati | File JSON su disco | Nessun database: snapshot + rapporti come file |
| Servizi | systemd (utente) | App sempre attiva + aggiornamenti schedulati |
Flusso dati (dati universo):
Gameforge API pubblica (XML + ?toJson=1)
│ ogni giorno (03:30)
▼
update_data.py ──► data/latest/*.json ──► world.json (indici)
│ ▲
└── highscore ── ogni ora (:17) ─────┘
│
app.py (Flask :8899) ──► browser (galassia/classifiche)
Flusso dati (rapporti di spionaggio):
In gioco (pulsante "API" del rapporto) ──► API string "sr-ar-170-<40 hex>"
│ incollata nella pagina
▼
POST /api/reports ──► report_store.py ──► proxy community (ogapi.faw-kes.de)
▼
data/reports/<sr_id>.json (+ index.json)
▼
clic sul pianeta in galassia ──► dettagli archiviati
2. Struttura delle directory
/opt/ogame_db/
├── app.py # Backend Flask: pagine + API + aggiornamento all'avvio
├── update_data.py # Download snapshot pubblici + classifiche + world.json
├── report_store.py # Import/archivio/consultazione rapporti di spionaggio
├── technames.py # Nomi tecnologici (edifici/ricerche/navi/difese) lato server
├── config.json # Configurazione (universo, proxy, account personale)
├── requirements.txt # Dipendenze Python
├── README.md # Guida rapida d'uso
├── DOCUMENTAZIONE.md # (questo file)
├── data/
│ ├── latest/ # Snapshot correnti + world.json
│ ├── snapshots/ # Storico giornaliero (ritenzione: keep_snapshots)
│ └── reports/ # Rapporti importati (1 file = 1 rapporto) + index.json
└── static/
├── index.html # Pagina galassia
├── rankings.html # Pagina classifiche
├── style.css # Stili (tema spaziale, responsive)
├── common.js # Utility condivise (fetch, avatar SVG, icone, stelle)
├── app.js # Logica della galassia e dei rapporti
├── rankings.js # Logica della pagina classifiche
├── icons.js # Icone SVG incorporate (game-icons, CC BY 3.0)
└── icons/ # (riservata a eventuali svg esterni; non usata a runtime)
3. config.json — configurazione
{
"server_number": 170, // numero universo
"community": "ar", // community (lingua/regione)
"domain": "s170-ar.ogame.gameforge.com",
"my_player_id": 100634, // tuo account: pianeti evidenziati in verde
"my_player_name": "MaNaki",
"proxy_base": "https://ogapi.faw-kes.de", // proxy ufficiale per i rapporti
"refresh_hours": 24, // dati "stale" oltre N ore → update all'avvio
"keep_snapshots": 30 // giorni di storico conservati
}
4. Backend — moduli Python
4.1 app.py — server Flask (porta 8899)
Avviato da systemd come ogame-galaxy.service. All'avvio verifica l'età dei dati
(_ensure_fresh_data) e, se più vecchi di refresh_hours, lancia update_data.main().
Middleware
| Funzione | Descrizione |
|---|---|
_no_cache(resp) |
after_request: imposta Cache-Control: no-store su pagine e file statici (niente cache nel browser) |
Helper
| Funzione | Descrizione |
|---|---|
load_config() |
Legge config.json |
load_world() |
Legge data/latest/world.json e vi fonde i pianeti noti solo dai rapporti (player recenti assenti da universe.xml), marcandoli report_only |
fmt_ts(epoch) |
Converte epoch in stringa YYYY-MM-DD HH:MM UTC |
_report_view(rec, full) |
Trasforma un record d'archivio + payload in una vista sintetica per la UI (date, attività, risorse, conteggi per categoria, flag failed_*) |
_ensure_fresh_data() |
Aggiornamento automatico all'avvio se i dati sono datati |
Endpoint HTTP
| Rotte | Descrizione |
|---|---|
GET / |
Pagina galassia (static/index.html) |
GET /rankings |
Pagina classifiche (static/rankings.html) |
GET /api/bootstrap |
Stato: server (nome, galassie, sistemi, velocità…), myPlayer, fetched (date ultimo aggiornamento per fonte), reportStats (n. rapporti/pianeti) |
GET /api/galaxy?g=&s= |
Celle del sistema (15 posizioni): per ogni cella pianeta, luna, giocatore (+stato, alleanza, rank totale/armamenti), rapporti disponibili |
GET /api/planet?g=&s=&p= |
Dettaglio pianeta: info, giocatore con rank, altri pianeti dello stesso giocatore, rapporti del pianeta e della luna |
GET /api/player?id= |
Dettaglio giocatore: tutti i suoi pianeti e tutti i rapporti (su qualunque pianeta o luna), ordinati per data |
POST /api/reports |
Importa un rapporto: body {"token": "sr-ar-170-<id>"} (o solo l'id a 40 hex). Idempotente: se già presente ritorna created:false |
GET /api/reports/<sr_id> |
JSON completo di un rapporto archiviato ({meta, report}) |
DELETE /api/reports/<sr_id> |
Elimina un rapporto archiviato (file su disco + voce in index.json) |
GET /api/rankings?type=&status=&start=&end=&q= |
Classifiche filtrate (vedi 4.4) |
POST /api/refresh |
Forza update_data.main() in background |
4.2 update_data.py — aggiornamento dati
Scarica l'API pubblica ufficiale di Gameforge (endpoint XML con ?toJson=1).
Costanti
| Costante | Valore |
|---|---|
ENDPOINTS |
serverData, universe, players, alliances, localization |
HIGHSCORES |
highscore_total (cat.1, type 0), highscore_military (cat.1, type 3) |
UA |
User-Agent dichiarato nelle richieste |
Funzioni
| Funzione | Descrizione |
|---|---|
load_config() |
Legge config.json |
http_get(url, timeout) |
GET con User-Agent |
fetch_xml_json(cfg, name, query) |
Scarica https://s<num>-<comm>.ogame.gameforge.com/api/<name>.xml?toJson=1<query> e aggiunge _fetched_at |
fetch_endpoint(cfg, name) |
Wrapper per gli endpoint semplici |
fetch_highscore(...) |
(helper storico) scarica un highscore |
save_latest(name, data) |
Salva in data/latest/<name>.json |
save_snapshot(name, data) |
Copia giornaliera in data/snapshots/<name>_<AAAA-MM-GG>.json (una per giorno; prune oltre keep_snapshots) |
_as_dict(payload, key, attr_key) |
Normalizza {"player":[{"@attributes":{...}}]} → {id: {...}} |
build_world(cfg) |
Costruisce world.json (vedi §6) |
_file_time(name) |
Epoch dell'ultimo fetch di un file latest |
update_highscores(cfg, with_snapshot) |
Scarica i 2 highscore |
main() |
Esegue l'aggiornamento; con argomento --highscore-only aggiorna solo le classifiche (usato dal timer orario) |
4.3 report_store.py — archivio rapporti di spionaggio
Gestisce il ciclo di vita dei rapporti: parsing API string → recupero dal proxy → salvataggio JSON → indicizzazione per coordinate.
Funzioni
| Funzione | Descrizione |
|---|---|
load_config() |
Legge config.json |
_load_index() / _save_index(idx) |
Legge/scrive data/reports/index.json |
parse_token(token, cfg) |
Valida l'API string (cr|sr|rr|mr)-<comm>-<num>-<40hex>; verifica che community/server combacino con la config; accetta anche il solo id esadecimale (assunto sr) |
fetch_from_proxy(api_string, cfg) |
GET {proxy}/v1/report/{api_string}/1; gestisce 429 (limite proxy ~10 req/min) e RESULT_CODE != 1000 |
_defender_info(report) |
Estrae dal payload generic i dati del bersaglio (coordinate, tipo pianeta/luna, nomi, data evento, attività, % bottino) |
import_report(api_string, cfg) |
Parsa → scarica → salva data/reports/<sr_id>.json → aggiorna index.json. Ritorna (record, creato?). Idempotente |
get_report(rid) |
Legge il file completo {meta, report} |
delete_report(rid) |
Elimina un rapporto (file + indice, ripulisce by_coords). Ritorna True se rimosso |
list_by_coords(coords, scope) |
Elenca i rapporti di un pianeta. scope: planet | moon | all, ordinati per event_timestamp desc |
summary(rec) |
(utilità) alias del record sintetico |
stats(cfg) |
Conta rapporti totali e pianeti coperti |
4.4 Filtri /api/rankings
Parametri: type (total|military|fleet), status, start/end (range posizione), q (testo su nome giocatore, tag o nome alleanza).
Con type=fleet (Top Flotte) la classifica non usa gli highscore: elenca solo i
giocatori che hanno almeno un rapporto importato, ordinati per numero di navi.
Le navi sono sommate prendendo, per ogni pianeta/luna spiato, il rapporto più
recente (campo total_ship_count, memorizzato nell'indice all'import); la
posizione rank è quella della classifica flotte e il valore è in score.
Valori di status e relativa condizione sullo stato API:
| status | stato API ammesso |
|---|---|
all |
qualsiasi |
active |
(vuoto) |
inactive |
i, I |
vacation |
v |
vacation_inactive |
vi, vI |
admin |
a |
Nota UI: la pagina
/rankingsespone solo le voci Tutti (all), Attivi (active) e Inattivi (inactive). Gli altri valori restano accettati dall'API per compatibilità, ma non sono più selezionabili dall'interfaccia.
Le righe restituite includono: id, nome, stato, alleanza (tag+nome), posizione, punteggio, coordinate del primo pianeta (per l'avatar), numero pianeti, flag mine, numero di rapporti di spionaggio sul giocatore (reports) e coordinate del rapporto più recente (report_coords, usata per il salto dal badge "Spie").
4.5 technames.py — dizionario nomi tech (server)
Mappe id → nome per la numerazione client attuale (diversa da quella storica):
edifici 1–44, ricerca 106–199, navi 202–219, difese 401–503, edifici lifeform 11101+.
Nota: il frontend ha una copia aggiornata nei propri sorgenti (vedi §5.4, NAMES);
technames.py resta come riferimento/utilità lato server.
| Funzione | Descrizione |
|---|---|
_localized_names() |
Carica i nomi localizzati da data/latest/localization.json (fallback) |
item_name(category, tid) |
Nome di un elemento (IT → localizzato → "Categoria #id") |
category_name(cat) |
Etichetta della categoria |
5. Frontend — static/
5.1 common.js — utility condivise
| Funzione | Descrizione |
|---|---|
esc(s) |
Escape HTML |
num(v) |
Formatta numeri in stile italiano (1.234.567), — se nullo |
hashStr(s) |
Hash deterministico (per i colori degli avatar) |
api(path, opts) |
fetch JSON con gestione errori ({ok:false, error}) |
icon(name, size) |
Ritorna l'SVG inline dell'icona da window.ICONS (icons.js) con currentColor |
artSVG(seedKey, size, moon) |
Avatar pianeta/luna in SVG: colore scelto da palette in base all'hash, con ombra e (per la luna) crateri |
initStars() |
Sfondo stellare su canvas (twinkle); non bloccante se canvas non disponibile |
5.2 app.js — galassia e rapporti
| Funzione | Descrizione |
|---|---|
loadBootstrap() |
Popola header: nome universo, range galassie/sistemi, date dati, conteggio spie |
loadGalaxy() |
GET /api/galaxy e render della tabella |
renderGalaxy(data) |
Costruisce le 15 righe: posizione, pianeta (avatar SVG + nome), luna, giocatore (colore per stato + 🏆/⚔ rank), alleanza, badge "spie" |
openPlanet(pos, focusMoon) |
Apre il popup del pianeta (GET /api/planet) |
openPlanetAt(coords, focusMoon) |
Apre il popup di un pianeta date le coordinate g:s:p, anche di un altro sistema |
openPlayer(pid) / renderPlayerPopup(d) |
Apre la finestra giocatore (GET /api/player): elenco di tutti i pianeti + tutti i rapporti di spionaggio sul giocatore, in un'unica vista |
renderPlanetPopup(data, focusMoon) |
Header con avatar; chip giocatore/stato/classifica/luna; altri pianeti del giocatore (cliccabili); griglia di card per gli spionaggi del pianeta e della luna |
rptCard(rec) |
Card riepilogo di un rapporto (data, attività colorata, bersaglio con coordinate [g:s:p], attaccante, conteggi con icone categoria) |
openReport(srId) / renderReportDetail(meta, rep) |
Vista dettaglio: risorse in tile colorate, meta (difensore/attaccante/attività/bottino/detriti), avvisi failed_*, sezioni in griglia di card con icona per ogni edificio/ricerca/nave/difesa |
techSection(...) |
Griglia card per categoria |
itemName(cat, id) / itemIconName(cat, id) |
Nome e chiave-icona di un elemento (fallback sulla categoria) |
actClass/actLabel(activity) |
Colore/etichetta dell'attività rilevata (0/15/30/60 min) |
fmtEv(evt) |
Data evento in formato locale italiano |
setSystem/setGalaxy/closePopup/goToCoords |
Navigazione (con clamp sui limiti universo) |
setMsg(kind, text) |
Messaggi di stato nella barra di import |
importReport() |
Legge l'API string, POST /api/reports, aggiorna la vista |
Stato globale: state = {galaxy, system, maxGalaxy, maxSystem, boot}.
All'avvio legge ?g= e ?s= dalla URL (usato dai click dalle classifiche).
Colori stato giocatore (come in galaxy OGame): attivo = giallo · inattivo (i/I) =
grigio · vacanza+inattivo = grigio · in vacanza = celeste · admin = rosso.
5.3 rankings.js — classifiche
| Funzione | Descrizione |
|---|---|
initHead() |
Header con nome universo e data aggiornamento classifiche |
load() |
GET /api/rankings con i filtri correnti |
render(d) |
Tabella: posizione (top3 colorati oro/argento/bronzo), avatar pianeta, giocatore (colore stato, ● = tu), alleanza, stato, pianeti, Spie (badge col numero di rapporti sul giocatore, cliccabile verso il pianeta del rapporto più recente), punti |
goGalaxy(coords) |
Salta alla galassia /?g=..&s=.. al pianeta del giocatore |
readFilters() |
Legge i controlli (stato, range, testo) |
Tabs: Generale (total), Armamenti (military) e Top Flotte (fleet — solo giocatori con rapporti, ordinati per navi), con icone SVG.
5.4 Mappe dati nel frontend (NAMES, ITEM_ICON)
NAMES[buildings|research|ships|defense|lfbuildings] → {id: nome} e
ITEM_ICON[...] → {id: chiave icona}. Nomi allineati al client attuale
(es. 213 → "Corazzata", 215 → "Incrociatore da battaglia",
210 → "Sonda di spionaggio").
5.5 icons.js / icone
window.ICONS = { chiave: {vb, body} } con 87 icone: 79 da game-icons.net
(CC BY 3.0, attribuzione nei footer) + icone UI custom (refresh, chevron, chiusura,
logo, avviso). Tutte usano fill="currentColor": il colore segue il CSS di categoria
(--tc), quindi nessuna dipendenza dai font emoji del sistema.
6. Dati su disco — data/
6.1 data/latest/*.json
Snapshot grezzi dell'API (serverData, universe, players, alliances,
localization, highscore_total, highscore_military), ciascuno con _fetched_at.
6.2 data/latest/world.json (indici precompilati)
| Chiave | Contenuto |
|---|---|
server |
numero, community, dominio, nome universo, galassie, sistemi, velocità, versione, lingua, timezone, ACS |
fetched |
epoch dell'ultimo fetch per ogni fonte |
players |
{id: {name, status, alliance, alliance_tag, alliance_name}} |
alliances |
{id: {name, tag, founder}} |
planets |
{"g:s:p": {id, player, name, coords, moon:{...}}}. Le voci con report_only: true non vengono dall'API pubblica ma da un rapporto di spionaggio (pianeti di player recenti assenti da universe.xml) |
avatar |
{playerId: prime-coordinate} (per gli avatar in classifica) |
ranks |
{playerId: {total, military, total_score, military_score}} |
6.3 data/snapshots/
Copie giornaliere *_AAAA-MM-GG.json per fonte (ritenzione configurabile).
6.4 data/reports/
index.json:{by_coords: {"g:s:p": [sr_id,…], "g:s:p#moon": [… ]}, reports: {sr_id: {meta…}}}→ ricerca immediata per pianeta/luna.<sr_id>.json:{"meta": {…}, "report": {generic, details}}(payload completo del proxy).
7. Servizi systemd (utente)
| Unità | Quando | Cosa fa |
|---|---|---|
ogame-galaxy.service |
sempre attivo | web app su 0.0.0.0:8899 (restart on failure) |
ogame-data-update.timer |
giornaliero 03:30 | update_data.py (pianeti/giocatori/alleanze + highscore) |
ogame-highscore.timer |
ogni ora (:17) | update_data.py --highscore-only (classifiche) |
Comandi utili: systemctl --user status/restart <unità>,
journalctl --user -u ogame-galaxy.service -f, loginctl show-user principale | grep Linger
(linger=yes ⇒ i servizi partono al boot senza login).
8. API esterne utilizzate
| Sorgente | Uso | Note |
|---|---|---|
https://s170-ar.ogame.gameforge.com/api/*.xml?toJson=1 |
API pubblica ufficiale: universe, players, alliances, serverData, localization, highscore | highscore.xml?category=1&type=0|3; cadenze server: universe ~settimanale, players ~giornaliero, highscore ~orario |
https://ogapi.faw-kes.de/v1/report/{api_string}/1 |
Proxy community ufficiale per il recupero dei rapporti (CR/SR/RR/MR) | Nessuna API key necessaria; limite ~10 richieste/min |
https://forum.origin.ogame.gameforge.com |
Documentazione ufficiale (thread "OGame API", procedure accesso) | Riferimento del protocollo |
9. Note operative e di sicurezza
- Accesso: app su
0.0.0.0:8899senza autenticazione: se la rete non è privata, mettere un reverse proxy con login. - Backup: copiare
data/(report inclusi) econfig.json. - Cache: i file statici sono serviti con
no-store: un refresh basta dopo ogni modifica (nessunCtrl+F5necessario, ma non guasta). - Privacy: i rapporti restano su questo server; il proxy viene contattato solo al momento dell'import di un nuovo token (che il giocatore controlla e condivide volontariamente).
- Licenza icone: game-icons.net, CC BY 3.0 (attribuzione nei footer di pagina).