Primo avvio
Questa è la sequenza unica di primo avvio per Moongate. Si applica sia installando il rilascio con l’installer Linux, sia usando l’immagine container, sia compilando dal sorgente. Moongate è in sviluppo attivo: i personaggi entrano nel mondo, camminano, si vedono tra loro e combattono, e NPC e oggetti eseguono script Lua, ma una parte del gameplay manca ancora. Vedi Stato dell’implementazione.
L’avvio del server richiede una radice, file client leggibili, il database PostgreSQL del ruolo attivo e SQL revisionato, e un’istanza Redis privata per lease dei realm e ticket di handoff monouso. I passaggi sotto preparano queste dipendenze.
Prima di iniziare
Section titled “Prima di iniziare”- I tuoi dati client Ultima Online. Moongate non li distribuisce. Il protocollo iniziale dei pacchetti è rivolto a ClassicUO con dati client UO 7.x.
- Una shell Unix come Bash o Zsh per gli esempi. Installa la CLI Bitwarden,
accedi al vault e sbloccalo con
BW_SESSIONimpostata in questa shell.bw statusdeve indicareunlocked; non stampa le password memorizzate. Mantieni disabilitato il tracing della shell (set +x) prima di caricare segreti. Fermati se una lettura dal vault fallisce. - Un server PostgreSQL raggiungibile su cui puoi creare database. Gli esempi di questo repository usano PostgreSQL 16.
- Un server Redis 7+ raggiungibile con autenticazione e
maxmemory-policy noeviction. Mantienilo su una rete privata. - Due porte TCP libere in modalità standalone: login usa normalmente 2593 e game 2595. Il server ping UDP usa la porta 12000 quando è libera.
- Per compilare dal sorgente: Git e l’SDK .NET 10 (
global.jsonimposta solorollForwardsulatestPatche rifiuta gli SDK prerelease; non fissa alcuna versione). Node.js serve solo per lavorare sul sito della documentazione.
Dove si trovano i comandi
Section titled “Dove si trovano i comandi”Per un primo server Linux, usa il percorso rilascio installato sotto. Scegli il sorgente solo per sviluppare Moongate; usa Docker se vuoi la topologia delle dipendenze fornita. Mantieni la directory di lavoro del percorso scelto per i suoi comandi:
-
Rilascio installato: completa l’installazione Linux. Esegui
mgctlemoongateda qualsiasi directory con i comandi installati nelPATH. -
Checkout del sorgente: esegui quanto segue dalla directory dove conservi i progetti, poi resta nella radice del repository per tutti i comandi
dotnetdi questa pagina:Terminal window git clone https://codeberg.org/moongate/moongate.gitcd moongategit switch developdotnet build Moongate.slnx -c Releasedevelopinclude lavoro non rilasciato. Per riprodurre un rilascio, esegui il checkout del suo tag e usa la documentazione pubblicata per quella versione. -
Docker: segui la ricetta completa login e realm, comprese configurazione, segreti, job dello schema e comandi di avvio. Torna a Collegarsi con ClassicUO per il profilo client. Per un singolo processo con database e Redis esistenti, usa Container standalone.
I passaggi sotto mostrano comandi completi per rilascio e sorgente. Esegui una sola
variante a ogni passaggio. Usano /srv/moongate come radice dei dati del server.
Primo avvio
Section titled “Primo avvio”-
Preparare la radice. Assegna al server una directory propria:
Terminal window sudo mkdir -p /srv/moongate && sudo chown "$USER" /srv/moongatemgctl init /srv/moongatePer un checkout del sorgente, sostituisci solo l’ultimo comando sopra con questo comando completo, eseguito dalla radice del repository:
Terminal window dotnet run --project src/Moongate.Server -c Release -- --initialize-root --root-directory /srv/moongateQuesto scrive
config/moongate.tomlcon i valori predefiniti, crealogs/eplugins/, copia l’SQL core del rilascio inmigrations/, i file dei dati dello shard indata/, i template intemplates/e gli script di esempio inscripts/. Non richiede database o file client. Preparare una radice con mgctl descrive cosa accade su una radice già esistente. -
Modificare la configurazione. Apri
/srv/moongate/config/moongate.tomle imposta percorso client ed entrambe le connessioni database. Mantieni le altre sezioni generate:[ultima]ultima_path = "/absolute/path/to/your/ultima-client"[persistence.accounts]connection_string = "$MOONGATE_ACCOUNTS_DATABASE"[persistence.realm]connection_string = "$MOONGATE_REALM_DATABASE"[redis]connection_string = "$MOONGATE_REDIS_CONNECTION_STRING"handoff_secret = "$MOONGATE_HANDOFF_SECRET"Usa un percorso client assoluto; i percorsi relativi si risolvono dalla directory di lavoro del processo, non dalla radice. Fornisci i due URI PostgreSQL, la stringa di connessione Redis e un segreto di handoff separato comune al cluster tramite le variabili d’ambiente referenziate. Il segreto deve avere almeno 32 byte UTF-8. Leggi le credenziali da Bitwarden; non scriverne i valori in questo file. Ogni processo login e game di un deployment richiede lo stesso endpoint Redis, password Redis e segreto di handoff. Il riferimento della configurazione elenca ogni impostazione.
La cifratura del client UO è disabilitata per impostazione predefinita. Per un client che invia traffico cifrato, configura
[network.encryption]usando la guida alla cifratura del client prima di avviare il server. Applica lo stesso profilo a processi login e game separati. -
Preparare PostgreSQL e Redis. Crea i database Accounts e World e credenziali specifiche per ruolo prima di avviare Moongate. Il server non crea mai database o ruoli. Usa un ruolo runtime solo DML e un ruolo schema separato; vedi Separare ruoli DDL e runtime.
Prepara Redis con password forte, accesso dalla rete privata e
maxmemory-policy noeviction. Tieni la password separata dal segreto di handoff. Per una topologia PostgreSQL e Redis eseguibile, usa l’ esempio Docker di login e realm. Standalone controlla entrambi i database; login controlla solo Accounts, e game solo il proprio Realm. Tutte e tre le modalità controllano anche Redis all’avvio. -
Applicare le migrazioni core con credenziali schema. Mantieni il server fermo. L’avvio rifiuta SQL in sospeso. Memorizza gli URI PostgreSQL completi schema e runtime in elementi Bitwarden distinti (gli esempi leggono il campo password di ciascun elemento). Sostituisci i nomi degli elementi sotto con i tuoi. Tutti e quattro gli URI devono puntare ai database creati al passaggio 3: Accounts per auth e Realm per world.
Carica prima nella shell principale le credenziali che userà l’avvio normale:
Terminal window export MOONGATE_ACCOUNTS_DATABASE="$(bw get password moongate-accounts-runtime-uri)"export MOONGATE_REALM_DATABASE="$(bw get password moongate-realm-runtime-uri)"export MOONGATE_REDIS_CONNECTION_STRING="$(bw get password moongate-redis-connection)"export MOONGATE_HANDOFF_SECRET="$(bw get password moongate-handoff)"Per il rilascio installato, applica l’SQL core revisionato in una subshell:
Terminal window (set -eMOONGATE_ACCOUNTS_DATABASE="$(bw get password moongate-accounts-schema-uri)"MOONGATE_REALM_DATABASE="$(bw get password moongate-realm-schema-uri)"export MOONGATE_ACCOUNTS_DATABASE MOONGATE_REALM_DATABASEmgctl migrate apply --root-directory /srv/moongate --target authmgctl migrate apply --root-directory /srv/moongate --target world)Per un checkout del sorgente, usa invece questa subshell dalla radice del repository:
Terminal window (set -eMOONGATE_ACCOUNTS_DATABASE="$(bw get password moongate-accounts-schema-uri)"MOONGATE_REALM_DATABASE="$(bw get password moongate-realm-schema-uri)"export MOONGATE_ACCOUNTS_DATABASE MOONGATE_REALM_DATABASEdotnet run --project src/Moongate.Ctl -c Release -- migrate apply --root-directory /srv/moongate --target auth --migrations-directory ./migrationsdotnet run --project src/Moongate.Ctl -c Release -- migrate apply --root-directory /srv/moongate --target world --migrations-directory ./migrations)Continua solo quando entrambe le applicazioni riescono.
--target authlegge[persistence.accounts],--target worldlegge[persistence.realm]dalla configurazione della radice. Le sostituzioni temporanee riguardano solo la subshell: quando termina, la shell principale conserva gli URI runtime. Non avviare il server nella subshell delle migrazioni. Disabilita il tracing della shell (set +x) quando gestisci segreti e non stampare queste variabili.Come proprietario dello schema, concedi ai ruoli runtime
CONNECTsul database,USAGEsugli schemi delle entità,SELECT,INSERT,UPDATE,DELETEsulle tabelle eUSAGEeSELECTsulle sequenze. Concedi soloUSAGEeSELECTsulla tabella della cronologia inmoongate_migrations, senza scritture della cronologia. Applica anche privilegi predefiniti per le tabelle future; Separare ruoli DDL e runtime descrive il contratto e la ricetta Docker fornisce script di provisioning. Moongate non concede questi diritti autonomamente.Usa
statusal posto diapplyper esaminare i file in sospeso. Ogniapplyriuscito riporta il numero applicato:Applied {count} migration(s) to {target}.L’opzione Applicare all’avvio richiede privilegi DDL; mantienila disabilitata in questa sequenza con ruolo runtime. -
Avviare il server.
Terminal window moongate --root-directory /srv/moongateOppure, dalla radice del repository sorgente:
Terminal window dotnet run --project src/Moongate.Server -c Release -- --root-directory /srv/moongateEntrambi i comandi usano le credenziali runtime della shell principale. Passa sempre
--root-directory. Senza, o con una radice uguale alla directory del binario, il server rifiuta l’avvio con codice di uscita 2, perché un aggiornamento sostituisce quella directory. Un avvio riuscito registraPostgres connection successfuluna volta per database, poi servizi caricati ed endpoint associati. Unscripts/init.luamancante è un avviso e avvia un ambiente di scripting vuoto; uno script bootstrap presente ma fallito impedisce l’avvio. Aggiungi script con Scrivere script Lua. I comandi della console interattiva sono elencati in Comandi del server. -
Creare il primo account. Nel terminale del server Login/Standalone in esecuzione, premi
*per sbloccare la console locale. Questa console viene trattata come Administrator, quindi può creare un account prima che qualcuno abbia effettuato il login. Salva una nuova password in Bitwarden, poi digita questo nella console del server, sostituendo entrambi i segnaposto (non digitarlo nella shell del sistema operativo):account create <username> <password> RegularLe password non possono contenere spazi. La console maschera la password ed esclude questa riga dalla cronologia. Attendi una conferma con il nome dell’account e
Regular; vedi account per livelli staff e disponibilità. L’accesso API non è necessario per il login di gioco. Per i tutorial staff sui contenuti, scegliGameMasterinvece diRegularquando crei l’account. -
Collegarsi ed entrare nel mondo. Segui Collegarsi con ClassicUO sotto mentre il server rimane in esecuzione. Conferma di poter creare un personaggio e camminare prima di arrestarlo.
-
Arrestarlo. Premi Ctrl+C e lascia terminare l’arresto. Dopo un avvio riuscito, l’host esegue un salvataggio finale del mondo prima di chiudere la persistenza PostgreSQL. Un avvio fallito o un game loop in errore non possono garantirlo. Non terminare il processo mentre lo attende. Il primo salvataggio dopo un avvio scrive l’intero mondo e richiede alcuni secondi (da 8 a 15 per quello distribuito); il server lo attende fino a 2 minuti dopo Ctrl+C o SIGTERM. Un salvataggio interrotto a metà non conferma nulla: ciò che è accaduto dall’ultimo salvataggio completato viene perso.
Collegarsi con ClassicUO
Section titled “Collegarsi con ClassicUO”Sul computer da cui giocherai, installa ClassicUO
e i tuoi dati client UO completi. Usa Edit Profiles → Add (o Create your first
profile) nel launcher ClassicUO e crea un profilo chiamato Moongate.
Le istruzioni ufficiali sui profili
spiegano dove compaiono questi campi.
| Campo del profilo | Valore per la prima connessione locale |
|---|---|
| IP del server | 127.0.0.1 quando client e server sono sullo stesso computer |
| Porta del server | 2593, il listener login, non la porta game |
| Directory UO | Percorso assoluto dei dati UO sul computer client |
| Versione client | La versione 7.x di quei file UO, indicata dal loro client.exe; non inventare una versione |
| Cifratura | Disabilitata (0), come nell’impostazione predefinita di Moongate |
Lascia disabilitati salvataggio delle credenziali e login automatico; inserisci
l’account del passaggio 6 nella schermata di login. Se avvii direttamente il client,
questi sono i campi corrispondenti da unire al suo settings.json esistente mentre ClassicUO è chiuso:
{ "ip": "127.0.0.1", "port": 2593, "ultimaonlinedirectory": "/absolute/path/to/your/ultima-client", "clientversion": "7.0.50.1", "encryption": 0, "saveaccount": false, "autologin": false}7.0.50.1 è un esempio: sostituiscilo con la versione effettiva dei tuoi dati.
Su Windows, usa il percorso client con backslash escapati per JSON. ClassicUO
documenta queste opzioni negli argomenti di avvio;
-settings può selezionare un file di impostazioni separato per questo shard.
- Avvia il profilo, inserisci nome account e password e collegati.
- Seleziona lo shard annunciato. Uno standalone predefinito elenca
Moongate(o il nome shard configurato); la ricetta Docker elenca i suoi due realm. Login reindirizza il client alla porta del game selezionato. - Seleziona uno slot personaggio vuoto, completa la creazione e scegli una città iniziale. Puoi invece selezionare un personaggio esistente.
- Attendi che compaia il mondo e muovi il personaggio. Vedere il personaggio e camminare conferma che login, redirect e ingresso nel mondo sono riusciti.
Per una connessione remota, inserisci nel profilo il nome DNS o IPv4 raggiungibile
del server invece di 127.0.0.1. Prima di avviare Moongate, imposta
realm_directory.advertised_address su un IPv4 raggiungibile dal client e
advertised_port sulla porta game raggiungibile (2595 per questo esempio standalone).
Lo standalone predefinito annuncia loopback, che funziona solo per un client sullo
stesso computer. Associa il server a un’interfaccia locale adatta con
network.listen_address e consenti/inoltra sia login TCP 2593 sia game TCP 2595
attraverso firewall/router. In Docker, pubblica queste porte e usa nell’annuncio la
porta game rivolta all’host. Una sola porta login raggiungibile non permette di
completare l’ingresso nel mondo. Vedi Configurazione e la
Topologia Docker.
Se il login riesce ma lo shard è assente, esamina l’avvio game e il lease Redis. Se la scelta dello shard non permette di collegarsi, controlla indirizzo annunciato e porta game. Per errori di dati client e avvio, usa Problemi comuni all’avvio.
Certificato amministrativo facoltativo
Section titled “Certificato amministrativo facoltativo”Per abilitare anche l’amministrazione facoltativa con un certificato TLS autofirmato, usa:
mgctl init /srv/moongate --generate-admin-certificate \ --admin-certificate-hosts "login.example.test"Sostituisci l’host di esempio con il nome DNS o l’indirizzo IP usato dal client
amministrativo; ometti --admin-certificate-hosts per il solo localhost. Questo
crea certificates/admin.pfx e il pubblico certificates/admin.crt, e aggiorna
esplicitamente quattro impostazioni [admin_api]. Il binding predefinito resta
127.0.0.1:2590. Vedi Configurazione del certificato
per fiducia del client, accesso dalla rete privata e riuso di un’identità esistente.
Rilasci precedenti
Section titled “Rilasci precedenti”mgctl è distribuito nei rilasci dopo 0.11.0; i rilasci da 0.7 a 0.11 hanno
invece mgboot <root>. Su 0.6.0, avvia invece il server una volta: scrive la
configurazione ed esce. Non serve altro, perché su 0.6.0 sia il server sia il
runner delle migrazioni leggono l’SQL core da /opt/moongate/migrations, accanto all’eseguibile:
moongate --root-directory /srv/moongateHelper per la build sorgente
Section titled “Helper per la build sorgente”Quando la radice è configurata, scripts/run_server.sh esegue compilazione e avvio
in un passaggio: pubblica una build Release del server e mgctl in dist/moongate,
esegue mgctl init sulla radice per aggiungere i file distribuiti mancanti, e vi avvia il server:
scripts/run_server.sh --root-directory "$HOME/moongate"--skip-build avvia la build già presente in dist/moongate, --build-only pubblica
senza avviare, e ogni altra opzione va al server invariata, per esempio
--pid-file-name game.pid.
Senza --root-directory lo script usa MOONGATE_ROOT. Ogni build elimina prima
dist/moongate, quindi non conservarvi nulla di tuo. Lo script esporta MOONGATE_ROOT
per una configurazione che nomina i percorsi tramite ${MOONGATE_ROOT}; un
MOONGATE_ROOT già impostato resta invariato anche quando --root-directory indica
un’altra radice, quindi rimuovilo dall’ambiente o passa lo stesso percorso.
Istanze aggiuntive
Section titled “Istanze aggiuntive”Per eseguire un’altra istanza standalone, assegnale una radice propria, porte
listener login e game distinte, realm_directory.realm_id e server_index distinti,
e un proprio database realm. Riutilizzare ID e indice predefiniti del realm
sostituisce il lease Redis della prima istanza. Non puntare mai due server alla
stessa radice o allo stesso database realm.
File e proprietà del processo
Section titled “File e proprietà del processo”Tutti i percorsi gestiti dal server sotto sono relativi a --root-directory:
| Percorso | Scopo |
|---|---|
config/moongate.toml |
Creato se mancante; il normale avvio lo conserva, mentre la configurazione esplicita del certificato aggiorna quattro impostazioni [admin_api] |
certificates/admin.pfx, certificates/admin.crt |
Identità TLS di amministrazione facoltativa di mgctl: PFX privato del server e PEM pubblico per la fiducia del client |
migrations/auth/, migrations/world/ |
SQL core copiato da mgctl init; i plugin distribuiscono il proprio sotto plugins/ |
data/ |
File dei dati dello shard copiati da mgctl, letti all’avvio game e standalone; vedi File dei dati dello shard |
templates/items/, loots/, carves/, mobiles/, npc_lists/, spawns/, decorations/, gumps/, books/, shops/ |
Template copiati da mgctl, caricati all’avvio game e standalone |
logs/moongate-*.clef |
Eventi di log JSON strutturati, uno per riga |
logs/errors/<id>.md |
Report di ogni eccezione registrata dal server, pronto da incollare in una issue |
plugins/ |
Un bundle assembly per directory plugin; installali e gestiscili con mgctl plugin |
scripts/ |
Sorgente Lua: un init.lua facoltativo, gli script mobile mobiles/<script_id>.lua, gli script oggetto items/<script_id>.lua, i moduli Lua condivisi in common/, gli script gump gumps/<id>.lua, gli script degli eventi stagionali events/<id>.lua, gli script delle abilità skills/<id>.lua, e i generati definitions.lua e .luarc.json |
moongate.pid |
Identificatore del processo corrente |
moongate.pid.lock |
File di lock usato per escludere un’altra istanza |
La protezione PID viene acquisita prima di caricare la configurazione. Un PID attivo
o un lock già detenuto rifiuta un altro avvio. Un PID obsoleto o malformato viene
sostituito. La protezione controlla se il processo è vivo, non l’identità dell’eseguibile,
quindi anche un PID riutilizzato può rifiutare l’avvio. Esamina quel processo prima
di modificare il file PID. La normale pulizia rimuove il file PID se appartiene
ancora a questo processo; il file .lock può restare dopo il rilascio del suo handle.
La sola presenza non significa che il server sia in esecuzione.
I log console mostrano ora, livello, sorgente e messaggio. I log su file ruotano ogni giorno e a 10 MiB, conservando fino a 30 file. Per le metriche vedi Diagnostica; per operazioni sullo schema e salvataggi del mondo vedi Persistenza PostgreSQL.
Quando qualcosa fallisce
Section titled “Quando qualcosa fallisce”La console mostra un’eccezione su una riga, messaggio e report, mai lo stack:
12:04:31.552 ERR BankService | Opening the bank failed: the bank box is missing - details: /srv/moongate/logs/errors/7f3a9c21aa.md (paste it into an issue)Il report contiene versione e nome in codice Moongate, sistema, runtime .NET, ora,
sorgente, livello, messaggio e l’intera eccezione, con eccezioni interne e stack,
in Markdown. Aprilo e incollalo in una
issue. Il nome
è l’hash dell’eccezione, così la stessa registrata di nuovo, per esempio da un timer,
riusa il report, che descrive la prima volta in cui è stata vista. Dopo 500 report
non ne vengono scritti di nuovi, così eccezioni con messaggi variabili non possono
riempire il disco; elimina i vecchi per fare spazio. In Docker il percorso è quello
interno al container, sotto la radice montata. Un wrapper come AggregateException
mostra il messaggio di ciò che contiene. I log .clef conservano l’eccezione completa
di ogni evento.
Problemi comuni all’avvio
Section titled “Problemi comuni all’avvio”| Sintomo | Controllo |
|---|---|
Esce subito dopo aver scritto config/moongate.toml |
Previsto su una radice nuova: ultima_path è ancora ChangeMe. Continua con il passaggio 2 |
| Errore del percorso client | Imposta ultima.ultima_path su dati client reali e leggibili |
Map ... needs map{n}.mul or map{n}LegacyMUL.uop, staidx{n}.mul and statics{n}.mul |
Al client manca quella mappa. Usa un client completo, o rimuovi la mappa da data/maps.toml |
The Ultima path has neither MultiCollection.uop nor multi.idx and multi.mul |
La directory client è incompleta. Punta ultima.ultima_path a un’installazione client completa |
tiledata.mul not found in the Ultima path |
La directory client è incompleta o non è una directory client. Punta ultima.ultima_path a un’installazione client completa |
| Errore di analisi o validazione TOML | Correggi il campo indicato; i file esistenti non vengono sostituiti silenziosamente |
Errore Postgres connection |
Il database non esiste, l’host è errato o il ruolo non può accedere. Dentro un container, localhost è il container stesso |
| Variabile di connessione mancante | Esporta le variabili PostgreSQL e Redis referenziate dalle sezioni TOML attive |
| Errore di connessione Redis | Controlla endpoint privato, credenziale, salute Redis e politica noeviction |
| Migrazioni in sospeso o modificate | Esegui status e apply del runner per la destinazione indicata (passaggio 4), o abilita persistence.auto_apply_migrations. Non modificare mai un file applicato |
| Necessarie modifiche allo schema PostgreSQL | Un’entità richiede DDL non fornito da alcuna migrazione. Genera e revisiona un file SQL versionato con --persistence-schema generate, poi applicalo con il runner a server fermo |
| Errore di binding della porta | Controlla network.listen_address, disponibilità delle porte e indirizzi delle interfacce |
| Rilevata un’altra istanza | Controlla PID e processo in esecuzione; usa una radice separata per un altro server |
... file ... not found per un file dati, come maps.toml |
La radice non ha data/. Riesegui mgctl sulla radice: aggiunge i file mancanti e mantiene gli altri |
InvalidDataException che indica un file dati |
Correggi la voce indicata dal messaggio; vedi le regole di validazione in File dei dati dello shard |
| Errore di avvio degli script | Correggi scripts/init.lua; controlla nome file e riga dello script nel log |
Creato con ❤️ da Tom
