Come modellare più "usi" (ad es. Arma) per inventario / oggetto / oggetti utilizzabili (ad es. Katana) all'interno di un database relazionale


10

Quindi sto lavorando per espandere gli usi degli articoli su www.ninjawars.net e non sono esattamente sicuro di come rappresentarli in modo flessibile nel database relazionale che utilizziamo.

Potrei abbaiare sull'albero sbagliato, quindi sentiti libero di dare suggerimenti in altre direzioni, ma attualmente sto pensando che ogni elemento dovrebbe avere "tag" relazionali.

Ad esempio, una Katana è attualmente una riga nel database "articoli". Per trasformarlo in un'arma e in una cosa utile, stavo pensando che avrei avuto un database di "tratti" e una tabella item_traits che si collegava semplicemente tra di loro.

// Objects and their basic data

item_id | item
1 | Naginata


// Things that objects can do

trait_id | trait
1 | weapon
2 | holdable

// How those objects do those things, e.g. powerfully, weakly, while on fire

_item_id | _trait_id | item_trait_data
1 | 1 | damage: 5, damage_type: sharp, whatever, etc

Non sono davvero sicuro di come modellare i dati extra che ne risultano (ad es. Il danno che una spada farà, il tipo di danno, ecc.).

Inoltre, non sono particolarmente felice che l'intero articolo venga archiviato in più di un posto, ad esempio per creare una copia di un oggetto con un nome diverso, come una "spada corta", dovrei copiare da più tabelle per creare l'elemento duplicato.

C'è un modo migliore per esporre questa roba che mi manca?

Modifica: dovrei solo notare che ho già un database postgresql in uso sul sito, motivo per cui voglio usarlo per la mia archiviazione di dati.

Modifica: ho aggiunto una risposta per l'implementazione che sto attualmente esaminando.

Risposte:


10

Non sarò leggermente in disaccordo con tutti e dirò che qui l'approccio relazionale è ragionevole. La cosa interessante qui è che gli oggetti possono avere più ruoli. Il problema principale sarà che la mappatura tra questo layout relazionale e un layout OO nel codice non sembrerà "naturale", ma penso che sul lato del database più ruoli possano essere espressi in modo pulito (senza strane codifiche o ridondanza, basta unire) .

La prima cosa da decidere è la quantità di dati specifica per l'elemento e la quantità condivisa da tutti gli elementi di un determinato tipo.

Ecco cosa farei se tutti i dati fossero specifici dell'articolo:

// ITEMS table: attributes common to all items
item_id | name        | owner         | location             | sprite_id | ...
1       | Light Saber | 14 (Tchalvek) | 381 (Tchalvek house) | 5663      | ...

// WEAPONS table: attributes for items that are weapons
item_id | damage | damage_type | durability | ...
1       | 5      | sharp       | 13         | ...

// LIGHTING table: attributes for items that serve as lights
item_id | radius   | brightness | duration | ...
1       | 3 meters | 50         | 8 hours  | ...

In questo disegno, ogni oggetto è nella tabella Articoli, insieme agli attributi che hanno tutti (o la maggior parte) degli articoli. Ogni ruolo aggiuntivo che un oggetto può svolgere è un tavolo separato.

Se vuoi usarlo come arma, lo guarderesti nel tavolo delle armi. Se è lì, è utilizzabile come arma. Se non è lì, non può essere usato come arma. L'esistenza del record ti dice se si tratta di un'arma. E se è lì, tutti i suoi attributi specifici dell'arma sono memorizzati lì. Poiché tali attributi sono memorizzati direttamente anziché in una forma codificata, sarai in grado di eseguire query / filtri con essi. (Ad esempio, per la pagina delle metriche del tuo gioco potresti voler aggregare i giocatori in base al tipo di danno dell'arma e potresti farlo con alcuni join e un tipo di danno_gruppo).

Un oggetto può avere più ruoli ed esiste in più di una tabella specifica per ruolo (in questo esempio, sia arma che illuminazione).

Se è solo un valore booleano come "è questo", lo metterei nella tabella Articoli. Potrebbe valere la pena memorizzare nella cache "è un'arma" ecc. Lì dentro in modo da non dover effettuare una ricerca sulle armi e su altri tavoli di ruolo. Tuttavia, aggiunge ridondanza, quindi è necessario fare attenzione a mantenerlo sincronizzato.

La raccomandazione di Ari di avere una tabella aggiuntiva per tipo può essere utilizzata anche con questo approccio se alcuni dati non variano per articolo. Ad esempio, se il danno dell'arma non varia per oggetto, ma i ruoli variano comunque per oggetto, puoi fattorizzare gli attributi dell'arma condivisa in una tabella:

// WEAPONS table: attributes for items that are weapons
item_id | durability | weapon_type
1       | 13         | light_saber

// WEAPONTYPES table: attributes for classes of weapons
weapon_type_id | damage | damage_type
light_saber    | 5      | energy

Un altro approccio sarebbe se i ruoli interpretati dagli oggetti non variano in base all'oggetto, ma solo al tipo di elemento. In tal caso, inseriresti item_type nella tabella Items e puoi archiviare le proprietà come "è un'arma" e "è conservabile" e "è una luce" in una tabella ItemTypes. In questo esempio faccio anche che i nomi degli articoli non cambino per articolo:

// ITEMS table: attributes per item
item_id | item_type    | owner         | location
1       | light_saber  | 14 (Tchalvek) | 381 (Tchalvek house)

// ITEMTYPES table: attributes shared by all items of a type
item_type   | name        | sprite_id | is_holdable | is_weapon | is_light
light_saber | Light Saber | 5663      | true        | true      | true

// WEAPONTYPES table: attributes for item types that are also weapons
item_type   | damage | damage_type
light_saber | 5      | energy

È probabile che gli oggetti e i tipi di armi non cambino durante il gioco, quindi puoi semplicemente caricare quelle tabelle in memoria una volta e cercare quegli attributi in una tabella hash invece che con un join al database.


+1. Questa è l'unica risposta che utilizza un database relazionale come database relazionale. Qualsiasi cosa diversa da questo o dall'altro estremo del suggerimento BLOB di Nevermind e solo l'utilizzo del DB come archivio dati, sono piani orribili.

+1 Ma questi approcci sembrano poco flessibili. Mi scuso se sembro incoerente, ma voglio essere in grado di creare le strutture del database per gli elementi essenzialmente una volta ... ... e quindi codificare più funzionalità per gli articoli, fare più inserimenti nel database per gli articoli, ma non è necessario cambiare il database di nuovo in futuro (con rare eccezioni, ovviamente).
Kzqai,

Se si desidera che il database relazionale sia a conoscenza dei propri campi e ne ottimizzi la rappresentazione, è necessario aggiungerli da qualche parte. È come tipi statici. Se vuoi che il tuo compilatore sia a conoscenza dei tuoi campi e ottimizzi la loro rappresentazione, devi dichiarare i tipi. L'alternativa è un approccio tipizzato in modo dinamico, utilizzato da alcuni dei database dei documenti o codificando i dati nel database relazionale in qualche modo. Il database non saprà quali sono i campi o non sarà in grado di ottimizzarne l'archiviazione, ma otterrai una certa flessibilità.
entro il

4

Sfortunatamente, situazioni come questa sono quelle in cui i database relazionali (come SQL) non sono all'altezza e i database non relazionali (come MongoDB ) eccellono. Detto questo, non è impossibile modellare i dati in un database relazionale e poiché sembra che la tua base di codice sia già dipendente da SQL, ecco il modello con cui andrei:

Invece di creare un elemento e utilizza una tabella, crea una tabella e una tabella di riferimento "[item] _type" per ciascun tipo di elemento.

Ecco alcuni esempi:

weapon_type_id | weapon_type
1 | sharp

weapon_id | weapon| weapon_type_id | damage
1 | Short Sword | 1 | 5

potion_type_id | potion_type
1 | HP
2 | Mana

potion_id | potion| potion_type_id | modifier
1 | Healing Elixer | 1| 5
2 | Mana Drainer | 2| -5

Questa soluzione offre molta flessibilità e scalabilità a lungo termine, riduce (se non elimina) lo spazio sprecato ed è auto-documentante (diversamente da "item_use_data"). Implica un po 'più di configurazione da parte dello sviluppatore, ma, a mio avviso, è la soluzione più elegante disponibile per le situazioni in cui è necessario utilizzare un database relazionale per archiviare i dati. In generale, i database non relazionali sono molto migliori per lo sviluppo di giochi, poiché sono più flessibili nel modo in cui modellano i dati, pur essendo più performanti dei database basati su SQL, rendendoli una scelta "vantaggiosa per tutti".

Modifica 1: corretto un errore con il campo potion_type_id

Modifica 2: Aggiunti maggiori dettagli sui database non relazionali vs relazionali per fornire una prospettiva aggiuntiva


Non vedo davvero molta flessibilità uscire da quel sistema. Ad esempio, se volessi una fiala di vetro, in grado di essere utilizzata come arma e di essere "acuta" ... ... sarei sfortunata. Inoltre, per ogni nuovo tipo di elemento, dovrei effettivamente creare una struttura di database per questo. Anche se ce ne fossero solo uno o due del tipo.
Kzqai,

I punti sollevati sono molto validi ed evidenziano ulteriori esempi del perché i database relazionali non si adattano bene a questa situazione specifica. Il modello che ho presentato mostra semplicemente il modo migliore di disporre i dati in modo tale da conservare la memoria e conservare la funzionalità SQL. Per archiviare oggetti di più tipi, il modo migliore per rappresentare quei dati in questo modello sarebbe quello di creare una tabella potion_weapon con le proprietà appropriate di pozioni e armi. Ancora una volta, questa soluzione NON è l'ideale, ma è la soluzione più elegante quando si utilizza un database relazionale.
Ari Patrick,

@Ari: nessuna mancanza di rispetto, ma il suo problema è proprio il motivo per cui l'approccio relazionale è più valido, non meno. È noto che i database NoSQL (o NoRel) sono ottimi per letture ad alto volume, dati distribuiti / altamente disponibili o schemi mal definiti. Questo caso è semplicemente una classica associazione molti-a-molti, e dbs come Mongo non lo fanno così come un RDBMS. Vedere stackoverflow.com/questions/3332093/...
alphadogg

@alphadogg Com'è questa relazione molti-a-molti? Nel database, le armi conoscono i tipi di armi, ma i tipi di armi non hanno bisogno di conoscere le armi a cui sono associati. Se per qualche motivo vuoi conoscere tutte le armi che appartengono a un tipo di arma specifico, scrivi semplicemente una query che scorre sulla raccolta di documenti dell'arma.
Ari Patrick,

@Ari: Nella domanda del PO un'arma può avere molti tipi e un tipo può essere collegato a molte armi. Ad esempio, una pozione e una spada sono sostenibili. Una spada è sia impugnabile che un'arma.
alphadogg,

3

Prima di tutto, scarica l'approccio di ereditarietà orientato agli oggetti e scegli un sistema basato su componenti .

Una volta fatto, il layout SQL diventa improvvisamente molto più semplice. È disponibile una tabella per ciascun tipo di componente con un numero ID condiviso. Se si desidera l'articolo n. 17, cercare "ID articolo 17" in ogni tabella. Ogni tabella che ha una chiave ottiene il suo componente aggiunto.

La tabella degli oggetti contiene tutti i dati richiesti per gli articoli in generale (nome, prezzo di vendita, peso, dimensioni, qualsiasi altra cosa condivisa tra tutti gli articoli). La tabella delle armi contiene tutti i dati appropriati per le armi, la tabella delle pozioni contiene tutti i dati appropriati per pozioni, la tua tabella Armature contiene tutti i dati appropriati per l'armatura. Vuoi una corazza, questa è una voce in Oggetto e una voce in Armatura. Vuoi un elmo della spada che puoi bere, hai appena inserito una voce in ogni tavolo e bam, il gioco è fatto.

Tieni presente che questo stesso modello non è particolarmente specifico per l'oggetto: puoi usarlo per creature, zone e qualsiasi altra cosa tu possa desiderare. È sorprendentemente versatile.


2

L'uso di SQL è stato il tuo grave errore. NON è assolutamente adatto per la memorizzazione di dati di progettazione di giochi statici.

Se non riesci ad allontanarti da SQL, prenderei in considerazione la memorizzazione di elementi in una serializzata da. ie

item_id (int) | item (BLOB)
1             | <binary data>

Certo, è brutto e getta tutte le "bellezze" SQL fuori dalla finestra, ma ne hai davvero bisogno ? Molto probabilmente, leggi tutti i dati dei tuoi oggetti all'inizio del gioco, e mai SELECTper niente diverso da item_id.


3
Dal momento che (dal mio punto di vista) il gioco è multiplayer e supporta PvP, è probabile che la maggior parte delle informazioni di gioco non siano memorizzate sul client. Se questo è accurato, ogni volta che i dati vengono letti dalla tabella, dovranno essere deserializzati prima di essere remotamente utili. Di conseguenza, questo formato rende MOLTO costoso la ricerca degli articoli in base alle loro proprietà; ad esempio: se si desidera recuperare tutti gli elementi di tipo "arma", è necessario recuperare tutti gli oggetti, deserializzarli tutti, quindi filtrare manualmente per il tipo di "arma", anziché eseguire una semplice query .
Ari Patrick,

1
Dalla mia esperienza, comunque, tutti gli elementi vengono letti nella cache in memoria all'inizio del gioco. Quindi li deserializzi solo una volta all'avvio e non usi affatto il database in seguito. Se non è così in questo caso, sono d'accordo, archiviare oggetti serializzati è una cattiva idea.
Nevermind

Hmmm, l'unica cosa è che questo mi lascia con un'interfaccia - necessaria - per modificare i dati, il che sarebbe scomodo.
Kzqai,

2

A seconda del numero di tratti che probabilmente ti serviranno, potresti usare una semplice maschera di bit per oggetti con i diversi bit corrispondenti a tratti diversi:

000001 = holdable
000010 = weapon
000100 = breakable
001000 = throwable
010000 = solids container
100000 = liquids container

Quindi è possibile eseguire test di bit semplici per vedere se un oggetto può essere utilizzato per una determinata funzione.

Quindi la "bottiglia di vetro" potrebbe avere un valore di 101111, il che significa che può essere usata, può essere usata come arma, si rompe facilmente, puoi lanciarla e contenere liquidi.

Qualsiasi editor creato per gli elementi può quindi disporre di un semplice set di caselle di controllo per abilitare / disabilitare i tratti su un oggetto.


1
Mi piace l'idea, perché consente a un elemento di contenere i propri tratti e non so che dovrò cercare nel database i tratti, ma non sono sicuro di come farlo funzionare in un contesto relazionale. Immagino che ogni bit si
associerebbe

Immagino che il bitmasking sia più utile per un numero fisso di tratti, però?
Kzqai,

Così tanto. Cosa succede se hai esaurito il tuo ultimo "bit"? Quanto è facile aumentare il tipo di dati per guadagnare bit e percolarlo attraverso il livello dell'app o aggiungere una colonna e fare lo stesso? Inoltre, il tuo particolare motore di database è ottimizzato per l'indicizzazione delle operazioni a bit? È meglio in un database relazionale rimanere atomico con colonne di dati. Non raggruppare più domini in una colonna. Non puoi sfruttare i vantaggi della piattaforma.
alphadogg,

1
Se volessi una tabella di ricerca nel DB per i tratti (probabilmente una buona idea in quanto puoi quindi aggiungerli dinamicamente a qualsiasi editor allora) allora avrebbe solo qualcosa del genere: id, maschera di bit, descrizione. 1,1, "holdable"; 2,2, "arma"; 3,4, "Breakable", ecc. Per quanto riguarda il numero fisso, sì, questo è vero. Ma se usi un int a 64 bit dovresti avere un sacco di spazio.
Muttley,

1

Nel nostro progetto abbiamo item_attributes per i diversi "dati extra" che un articolo può avere. È presentato qualcosa del genere:

item_id | attribute_id    | attribute_value | order 
1        25 (attackspeed)       50             3    

Quindi abbiamo una tabella degli attributi che assomiglia a questo:

id |   name       | description
1    attackspeed    AttackSpeed:

Ari Patrick ha ragione, in definitiva i db relazionali non sono fatti per questo. Il rovescio della medaglia è che abbiamo alcune procedure piuttosto complesse per generare nuovi elementi (fatto tramite uno strumento esterno - che consiglio vivamente, non provare ad aggiungere manualmente questi, ti confonderai solo)

L'altra opzione che hai è usare un linguaggio di scripting per creare i template degli oggetti, quindi puoi analizzarli facilmente e usarli per creare nuovi elementi. Ovviamente devi ancora salvare i dati degli oggetti nel database ma a quel punto non devi preoccuparti delle specifiche della creazione di nuovi elementi, puoi praticamente semplicemente copiare e il vecchio file di script, modificare alcune informazioni e sei a posto andare.

Onestamente, se dovessimo rifare il modo in cui creiamo nuovi elementi statici, avremmo probabilmente optato per un approccio molto più semplice utilizzando i modelli di elementi di scripting.


1

Questa è la tipica relazione molti-a-molti, niente di troppo esoterico per qualsiasi database relazionale capace. Hai molti tratti per ogni oggetto e ogni tratto può essere usato da uno o più tipi di oggetti diversi. Modella tre relazioni (tabelle), una delle quali è una relazione di associazione e il gioco è fatto. Una corretta indicizzazione ti garantirà letture veloci dei dati.

Inserisci un ORM nel tuo codice e dovresti avere pochissimi problemi che vanno avanti e indietro tra DB e middleware. Molti ORM sono in grado di generare automaticamente anche le classi stesse, e quindi diventano ancora più "invisibili".

Per quanto riguarda i database NoSQL, non c'è motivo per cui non puoi farlo con quelli. Al momento è di moda fare il tifo per quella tecnologia negli stracci commerciali e nei blog, ma arrivano con una serie di problemi propri: piattaforme relativamente immature, ideali per semplici letture raramente modificate (come un twit uno-a-molti in un profilo) ma scarso per letture o aggiornamenti dinamici complessi, carenza di toolchain di supporto, dati ridondanti e problemi di integrità che li accompagnano, ecc. Tuttavia, offrono il fascino di una migliore scalabilità perché evitano in varia misura le capacità transazionali e le sue spese generali e modelli più facili di distribuzione / replica .

Il solito hobgoblin dei database relazionali rispetto ai database NoSQL sono le prestazioni. RDMBS diversi hanno diversi gradi di sovraccarico coinvolti che li rendono meno preferiti per il ridimensionamento ai livelli di Facebook o Twitter. Tuttavia, è molto improbabile che tu abbia affrontato questi problemi. Anche in questo caso, semplici sistemi server basati su SSD possono rendere inutile il dibattito sulle prestazioni.

Cerchiamo di essere chiari: la maggior parte dei database NoSQL sono tabelle hash sostanzialmente distribuite e ti limiteranno allo stesso modo di una tabella hash nel tuo codice, ad es. non tutti i dati si adattano bene a quel modello. Il modello relazionale è molto più potente per modellare le relazioni tra i dati. (Il fattore confondente è che la maggior parte dei RDBMS sono sistemi legacy scarsamente sintonizzati per le richieste del popolare 0,0001% del web, vale a dire Facebook et al.)


Se hai intenzione di fare riferimento a loro collettivamente, non preoccuparti nemmeno di parlare di database. NoSQL non è un'entità che può essere discussa in modo significativo, è un riferimento di massa inutile che i fanbois SQL usano per applicare la logica imperfetta che se a un database di questo gruppo definito manca una funzionalità, a tutti loro manca quella funzionalità.
aaaaaaaaaaaa,

NoSQL è il termine che gli spacciatori NoSQL hanno scelto di adattare. Non so perché, non è molto descrittivo. Ma non è una sorta di peggiorativo. Avendo lavorato con diversi, penso che la descrizione di alphadogg sia corretta.

Forse il mio commento è stato un po 'duro, tuttavia, odio quel nome e quel raggruppamento, è impossibile avere un dibattito qualificato sui dettagli più fini dei diversi sistemi di database quando le persone mantengono questa visione del mondo semplificata.
aaaaaaaaaaaa,

@eBusiness: trovo il tuo commento divertente, dato che è il campo anti-RDBMS, se ce n'è uno, a ungere il loro gruppo di tecnologie come "NoSQL". Certo, molti di loro vorrebbero vedere quel nome deprecato, col senno di poi. Soprattutto perché molti di loro stanno finalmente sovrapponendo SQL alle loro implementazioni fisiche. Per quanto riguarda parlare di loro, non ho preso il tuo commento come duro, o ho la pelle spessa, la tua scelta! :) Voglio dire, si può parlare del Tea Party, perché non il gruppo di database NoSQL?
alphadogg,

È giusto, riconosco che la relazione è totalmente da molti a molti. La cosa che mi impedisce di crearlo in uno stile veramente normalizzato è il pensiero che le "cose" che comporterebbero un oggetto verranno poi distribuite su almeno due tavoli. Non mi piace l'idea di non riuscire a creare inserti atomici, credo.
Kzqai,

0

È qui che trovo davvero utili mappatori OR più moderni, come Entity Framework 4 e la sua prima funzione di codice (CTP) . Devi solo scrivere le classi e le loro relazioni in codice normale e senza nemmeno doverle decorare o eseguire manualmente qualsiasi strumento, EF genererà il backing store in formato SQL per te, con le tabelle di link richieste e tutto il resto scatena la creatività imo ^^


Bene, creerò il codice e le classi e tutto ciò che nel codice solo prima ... ... devo solo tradurlo nella struttura di database esistente dopo.
Kzqai,

0

Ecco cosa sto prendendo in considerazione:

Dato che ogni "tratto" richiede essenzialmente modifiche nel codice, quindi ho deciso di conservare i tratti (e tutti i dati predefiniti che richiedono) nel codice stesso (almeno per ora).

Per esempio $traits = array('holdable'=>1, 'weapon'=>1, 'sword'=>array('min_dam'=>1, 'max_dam'=>500));

Quindi gli elementi ottengono un campo "trait_data" nel database che utilizzerà la json_encode()funzione per essere archiviato nel formato JSON.

item_id | item_name | item_identity | traits
1 | Katana | katana | "{"holdable":1,"weapon":1,"sword":{"min_dam":1,"max_dam":1234,"0":{"damage_type":"fire","min_dam":5,"max_dam":50,"type":"thrown","bob":{},"ids":[1,2,3,4,5,6,7]}}}"

Il piano è che gli elementi erediteranno tutte le statistiche predefinite dai tratti principali e avranno solo tratti di over-ride che specificano le differenze rispetto a quelle impostate come predefinite.

L'aspetto negativo del campo tratti è che mentre potrei modificare la parte json a mano ... ... non sarà davvero facile o sicuro farlo con i dati che si trovano nel database.


1
Cosa succede quando si introduce un nuovo tratto? Quanto spesso può succedere? Quali sarebbero gli effetti a valle sul carico di lavoro di manutenzione del codice? In contrasto con l'archiviazione come molti-a-molti per cui le istanze degli oggetti sono costruite in modo dinamico (tramite la tua scelta di ORM) per conservare quei dati.
alphadogg,

Grazie, questo è un buon punto, l'aggiunta di nuovi tratti non sarà banale. Hai aggiunto alla mia analisi la paralisi. : p
Kzqai,

Siamo spiacenti, ma questo è piuttosto critico. Devi solo pensarci su. Modella l'esercizio nella tua mente di cosa dovresti fare quando alcune armi devono essere aggiornate per aggiungere un nuovo tratto in modo che il tuo miglioramento del gioco possa funzionare.
alphadogg,

-1

Questo è un po 'confuso, e non garantisco che sia un buon design DB; le mie lezioni di DB erano un po 'di tempo fa e non mi vengono in mente in fretta. Ma se si garantisce che gli articoli hanno meno di 10 articoli, è possibile assegnare a ciascun articolo un campo attributo1 e un campo attributo2 e così via fino ad attributo10. Eliminerebbe la necessità della tabella degli attributi degli articoli molti-a-molti, al costo di limitare il numero di attributi.

Ripensandoci, sono abbastanza sicuro che sia un progetto terribile, ma significa che puoi rimanere con un comodo database relazionale e non dover andare in un territorio inesplorato. Sta a te decidere se ne vale la pena.


Questo è un design terribile, non farlo mai. Faresti meglio a non usare un database.
ZorbaTHut,

-1

Nevermind ha dato una buona risposta, ma mi chiedo, hai bisogno di un database per questo? Memorizzare tutti i dati in un file semplice e caricarli nel programma all'avvio sembra il modo più intelligente per farlo.

Modifica:
giusto, in un ambiente guidato da una richiesta senza stato è meglio conservare i dati in un database. Scrivi i tuoi dati in un file e scrivi un pezzo di codice per trasformarlo in un database del tipo suggerito da Nevermind.

In alternativa, se il numero di oggetti non è troppo grande, dichiarare il lotto letteralmente in un file di codice può essere il metodo più veloce.


Err, ho già un database in uso e integrato con il resto del sito.
Kzqai,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.