Modi per gestire la modifica dei dati dei designer insieme alla modifica dei dati dei giocatori


14

Ho un gioco online in cui i giocatori possono modellare il mondo in qualche modo, ad es. Gli alloggi di Ultima Online, dove puoi costruire le tue case direttamente su alcune parti della mappa del mondo. Questi sono cambiamenti che dovrebbero persistere nel tempo come parte del mondo persistente.

Allo stesso tempo, il team di progettazione sta aggiungendo nuovi contenuti e modificando i vecchi contenuti per migliorare ed estendere il gioco ai nuovi giocatori. Lo faranno prima su un server di sviluppo durante i test e poi dovranno unire il loro lavoro con il "lavoro" dei giocatori sul server live.

Supponendo di risolvere i problemi di progettazione del gioco, ad es. i giocatori possono costruire solo in aree designate, quindi non si scontrano mai geograficamente con le modifiche dei designer: quali sono i modi migliori per gestire i dati o organizzare le strutture dei dati in modo da evitare conflitti quando i dati dei nuovi designer vengono uniti a quelli dei nuovi giocatori?

Esempio 1: un giocatore crea un nuovo tipo di oggetto e il gioco gli assegna l'ID 123456. Le istanze di quell'elemento si riferiscono tutte a 123456. Ora immagina che i progettisti di giochi abbiano un sistema simile e un designer crei un nuovo oggetto anche numerato 123456. Come può essere evitato?

Esempio 2: qualcuno crea una mod popolare che dà a tutti i tuoi draghi un accento francese. Include uno script con un nuovo oggetto chiamato assignFrenchAccentche usano per assegnare le nuove risorse vocali a ciascun oggetto drago. Ma stai per distribuire il tuo DLC "Napoleon vs Smaug" che ha un oggetto con lo stesso nome: come puoi farlo senza molti problemi con il servizio clienti?

Ho pensato alle seguenti strategie:

  • È possibile utilizzare 2 file / directory / database separati, ma le operazioni di lettura sono notevolmente complicate. "Mostra tutti gli elementi" deve eseguire una lettura sul DB di progettazione e una lettura sul DB di lettore (e deve comunque distinguere tra i 2, in qualche modo).
  • È possibile utilizzare 2 spazi dei nomi diversi all'interno di un negozio, ad es. usare le stringhe come chiave primaria e prefissarle con "DESIGN:" o "PLAYER:", ma la creazione di questi spazi dei nomi può essere non banale e le dipendenze non sono chiare. (ad es. in un RDBMS potrebbe non essere possibile utilizzare in modo efficiente stringhe come chiavi primarie. È possibile utilizzare numeri interi e allocare tutte le chiavi primarie al di sotto di un determinato numero, ad esempio 1 milione, per essere dati di progettazione e tutto quanto sopra quel punto deve essere i dati del giocatore. Ma quelle informazioni sono invisibili all'RDBMS e i collegamenti delle chiavi esterne attraverseranno il "divario", il che significa che tutti gli strumenti e gli script devono aggirare esplicitamente.
  • Puoi sempre lavorare sullo stesso database condiviso in tempo reale, ma le prestazioni potrebbero essere scadenti e il rischio di danni ai dati dei giocatori potrebbe essere migliorato. Inoltre, non si estende ai giochi eseguiti su più di 1 server con dati mondiali diversi.
  • ... altre idee?

Mi viene in mente che, sebbene questo sia principalmente un problema per i giochi online, i concetti possono applicarsi anche al modding, in cui la community crea mod allo stesso tempo in cui gli sviluppatori modificano il proprio gioco. Ci sono strategie qui utilizzate per ridurre la possibilità di rottura del mod quando escono nuove patch?

Ho anche etichettato questo come "controllo della versione" perché a un livello è quello che sono: 2 rami dello sviluppo dei dati che devono essere uniti. Forse alcune intuizioni potrebbero venire da quella direzione.

EDIT: alcuni esempi aggiunti sopra per aiutare a chiarire il problema. Sto iniziando a pensare che il problema riguardi davvero lo spazio dei nomi, che potrebbe essere implementato in un negozio tramite chiavi composite. Ciò semplifica la strategia di unione, almeno. Ma potrebbero esserci delle alternative che non vedo.


1
Immagino che la risposta possa dipendere almeno in parte dal tipo di dati che i designer stanno aggiungendo e da cosa stanno aggiungendo i giocatori.
lathomas64,

Potrebbe, ma sono più interessato a soluzioni generiche per 2 parti che contribuiscono entrambe a un singolo archivio dati.
Kylotan,

1
A molte persone manca il punto di questa domanda - non sono le modifiche dei giocatori che sono in conflitto: piuttosto aggiornamenti del contenuto ecc. Che rompono i layout esistenti. @Kylotan ho ragione?
Jonathan Dickinson,

È qui che gli aggiornamenti dei contenuti degli sviluppatori si scontrano potenzialmente con gli aggiornamenti dei contenuti dei giocatori. Non sono molto interessato alle soluzioni alternative di progettazione del gioco (ad es. Consentire ai giocatori di costruire solo in determinati luoghi) ma alle soluzioni alternative della struttura dei dati (ad es. Consentire solo ai giocatori di creare oggetti con ID superiori a 1 milione).
Kylotan,

2
Non hai specificato, ti aspetti di fare aggiornamenti in tempo reale su un mondo dal vivo? Una nota a margine: 2 parti che contribuiscono a un singolo archivio di dati È un database, ecco cosa fanno i database, non si può aggirare quel fatto e sarebbe folle ignorare decenni di conoscenza su come evitare problemi con i dati condivisi.
Patrick Hughes,

Risposte:


2

Penso che le risposte che propongono soluzioni DB stiano saltando a un'implementazione specifica senza capire il problema. I database non rendono facili le fusioni, ti danno solo un framework in cui archiviare i tuoi dati. Un conflitto è ancora un conflitto anche se si trova in un DB. E il check-out è la soluzione di un uomo povero al problema: funzionerà, ma a un costo paralizzante per la tua usabilità.

Quello di cui stai parlando qui rientra nel modello di sviluppo distribuito del problema. Il primo passo, credo, non è pensare ai giocatori e ai designer come a tipi separati di creatori di contenuti. Ciò rimuove una dimensione artificiale del problema che non influisce sulla soluzione.

In effetti hai la tua linea principale: la versione canonica approvata dagli sviluppatori. Potresti (probabilmente) avere anche altre filiali: server live dove le persone stanno attivamente sviluppando e condividendo mod. Il contenuto può essere aggiunto su qualsiasi ramo. Fondamentalmente, i tuoi designer non sono niente di speciale qui - sono solo creatori di contenuti che vivono in casa (e puoi andare a trovarli e colpirli quando si rovinano).

Quindi accettare il contenuto generato dall'utente è un problema di unione standard. Devi ritirare le loro modifiche sulla linea principale, unirle, quindi estrarle di nuovo, oppure tirare le modifiche della linea principale sul loro ramo e unirle (lasciando la linea principale "pulita" delle cose generate dall'utente). Come al solito, andare al tuo ramo e sistemare lì è più amichevole che chiedere ad altre persone di apportare le modifiche e quindi provare a ripararlo da remoto alla loro estremità.

Una volta che lavori con quel tipo di modello, si applicano tutti i normali processi per evitare conflitti di unione. Alcuni dei più ovvi:

  • Incoraggiare l'uso liberale di spazi dei nomi per intercettare i contenuti di un particolare autore / mod / team.
  • Laddove il contenuto deve interagire, stabilire chiare convenzioni di chiamata / utilizzo, convenzioni di denominazione e altre "regole" sciolte che guidano lo sviluppo in modo che sia facile ricongiungersi. Fornire strumenti che consentano ai creatori di contenuti di sapere se stanno seguendo tali regole, idealmente integrati nella creazione stessa del contenuto.
  • Fornire strumenti di reporting / analisi per individuare i probabili problemi di unione prima che si verifichino. Ripararlo dopo la fusione è probabilmente molto doloroso. Fai in modo che un determinato bit di contenuto possa essere controllato e dato tutto chiaro come pronto per l'unione, in modo che l'unione sia indolore
  • Rendi robusta la tua fusione / integrazione. Consenti rollback facili. Esegui rigorosi test sui contenuti uniti: se falliscono i test, non unirli! Scorri i loro contenuti o i tuoi fino a quando l'unione procederà in modo pulito.
  • Evita di utilizzare gli ID interi incrementali per qualsiasi cosa (non hai un modo affidabile di distribuirli ai creatori). Funziona solo in un DB perché il DB stesso è un provider canonico di ID in modo da non ottenere duplicati; tuttavia introduce anche un singolo punto di errore / carico nel sistema.
  • Usa invece i GUID: costano di più per l'archiviazione, ma sono specifici della macchina e quindi non causeranno collisioni. In alternativa, utilizzare identificatori di stringhe, questo è molto più facile da debug / risolvere, ma più costoso per l'archiviazione e il confronto.

Purtroppo un po 'di tutto ciò non è di aiuto al mio problema (es. Avere giocatori che seguono determinate regole, dato che tutto deve essere fatto automaticamente sul lato server) e non penso che sarà pratico supportare il grado di gestione delle fusioni e delle transazioni semantica menzionate, ma l'approccio generale di allocazione di ID univoci garantiti, forse GUID, è probabilmente il più vicino a quello con cui andrò.
Kylotan,

Ah, capisco. Bene, dal momento che controlli i loro strumenti di costruzione, applicare almeno gli approcci di fusione (spazi dei nomi, ecc.) È qualcosa che puoi fare senza che i giocatori debbano essere d'accordo.
MrCranky,

Cosa fai se due giocatori creano contenuti duplicati? O le istanze separate del tuo mondo di gioco sono trattate come uniche? Nel qual caso, forse è un approccio utile controllare automaticamente ogni istanza unica che conosci contro il tuo ramo core / mainline per i conflitti che si verificheranno quando invii tali modifiche alle istanze. Se non riesci a controllare i giocatori, puoi almeno avvisare la tua squadra interna che il lavoro che stanno svolgendo è in conflitto con l'istanza X del mondo, all'inizio dello sviluppo.
MrCranky,

Il concetto di spazi dei nomi non è tanto il problema: scegliere lo spazio dei nomi adeguato dallo spazio dei nomi di tutti i possibili spazi dei nomi! :) E i contenuti duplicati per me non sono un problema: sono solo 2 istanze di qualcosa che sono equivalenti. L'importante è che non si verifichino fusioni o sovrascritture dannose. Per quanto riguarda i controlli automatici delle collisioni, ciò arresta il danno fatto nella scrittura, ma non risolve il problema di denominazione originale. (Rinominare le cose per evitare una collisione può essere non banale, a causa di riferimenti incrociati.)
Kylotan,

Ah sì, vedo ora, non sono gli spazi dei nomi stessi quanto la scelta del nome. In tal caso, i GUID sono probabilmente di nuovo la risposta: il contenuto è effettivamente contenuto nella sua piccola area. È possibile assegnare un nome decorativo, ma il gioco utilizzerà il GUID.
MrCranky,

1

Conserva tutto come un attributo (o decoratore) - con punti di montaggio. Prendiamo una casa che il giocatore ha progettato come esempio:

o House: { Type = 105 } // Simple square cottage.
 o Mount point: South Wall:
  o Doodad: Chair { Displacement = 10cm }
   o Mount point: Seat:
    o Doodad: Pot Plant { Displacement = 0cm, Flower = Posies } // Work with me here :)
 o Mount point: North Wall:
  o Doodad: Table { Displacement = 1m }
    o Mount point: Left Edge:
     o Doodad: Food Bowl { Displacement = 20cm, Food = Meatballs}

Quindi ogni entità può avere uno o più punti di montaggio - ogni punto di montaggio può accettare zero o più altri componenti. Questi dati verrebbero archiviati con la versione in cui sono stati salvati, insieme a tutte le proprietà pertinenti (come Displacement ecc. Nel mio esempio) - NoSQL probabilmente si adatterebbe molto bene qui (Key = ID entità, Valore = Binario serializzato Dati).

Ogni componente dovrebbe quindi essere in grado di "aggiornare" i vecchi dati da una versione precedente (non rimuovere mai i campi dai dati serializzati - solo "null") - questo aggiornamento avviene nel momento in cui viene caricato (verrebbe quindi immediatamente archiviato nuovamente in l'ultima versione disponibile). Diciamo che la nostra casa ha cambiato le sue dimensioni. Il codice di aggiornamento determinerebbe relativamente la distanza tra le pareti nord e sud e altererebbe proporzionalmente gli spostamenti di tutte le entità contenute. Come altro esempio, la nostra ciotola di carne potrebbe aver rimosso il campo "Cibo" e ottenere invece una "Varietà" (Carne) e "Ricetta" (Palline). Lo script di aggiornamento trasformerebbe "Meat Balls" in "Meat", "Balls". Ogni componente dovrebbe inoltre sapere come gestire le modifiche ai punti di montaggio, ad es

Tutto ciò lascia esattamente un problema aperto: cosa succede se due oggetti si scontrano tra loro (non il loro contenitore - i punti di montaggio ti proteggono da quello)? Dopo un aggiornamento, dovresti controllare le collisioni e tentare di risolverle (spostando le cose a parte, un po 'come SAT). Se non riesci a capire come risolvere la collisione, rimuovi uno degli oggetti e mettilo in una riserva - dove possono acquistare questi oggetti rimossi (gratuitamente) o venderli (a prezzo pieno); e ovviamente avvisare il giocatore che l'aggiornamento ha interrotto parte del loro layout, possibilmente con una funzione di "zoom in" in modo che possano vedere il problema.

Alla fine dovresti lasciare cambiamenti complessi nelle mani dei giocatori (fallire velocemente) poiché nessun algoritmo può rendere conto dell'estetica - dovresti semplicemente essere in grado di fornire al giocatore il contesto di dove si trovava l'oggetto (in modo che possano ricordare, non solo atterrare con tutti questi oggetti nella loro scorta e non sapere dove fossero).


Questo è focalizzato un po 'troppo sul posizionamento degli oggetti, che non è proprio il problema chiave che sto cercando di risolvere. Si tratta più di avere identificatori univoci in set di dati simultanei e di dover essere in grado di unire quelli senza alcun possibile rischio di conflitto. Ho aggiunto 2 esempi al mio post l'altro giorno per cercare di spiegare un po 'di più.
Kylotan,

1

Sto cercando di associare questo a qualcosa che capisco, quindi sto pensando in termini di Minecraft in questo momento. Sto immaginando un server live con i giocatori che apportano modifiche in tempo reale mentre gli sviluppatori sono in esecuzione su un server di prova che corregge / crea nuovo contenuto.

La tua domanda sembra quasi 2 domande uniche:

  1. Come assicurare che gli ID oggetto siano univoci
  2. Come assicurarsi che gli spazi dei nomi degli script non si scontrino

Vorrei provare a risolvere il n. 1 attraverso un sistema di riferimento temporaneo. Ad esempio, quando un nuovo oggetto viene creato da qualcuno, potrebbe essere contrassegnato come volatile o temporaneo. Immagino che tutti i nuovi contenuti creati sul server di prova vengano contrassegnati come volatili (sebbene possa anche fare riferimento a contenuti non volatili).

Quando sei pronto a portare nuovi contenuti sul server live, il tuo processo di importazione trova gli oggetti volatili e assegna loro gli ID degli oggetti del server live che sono impostati su pietra. Ciò è diverso dall'importazione / unione diretta poiché è necessario poter fare riferimento a oggetti non volatili esistenti nel caso in cui sia necessario correggerli o aggiornarli.

Per il n. 2, sembra che tu abbia davvero bisogno di avere un certo livello di trasmutazione intermedia degli script che può eseguire l'hashing del nome della funzione in un unico spazio dei nomi. vale a dire

assignFrenchAccent

diventa

_Z11assignFrenchAccent

0

Se i file per i dati sono di testo anziché binari e designer e lettori stanno modificando aree diverse, è possibile provare a unire SVN.


0

Penso che un database / filesystem replicato in ambienti con una procedura di "check-out" sarebbe il migliore.

Pertanto, ogni volta che un designer desidera apportare alcune modifiche al mondo, verificherebbe / bloccherebbe tutte le risorse che desidera creare / modificare su tutte le copie del database (sviluppo e produzione), quindi nessun altro giocatore o designer potrebbe modificarlo . Avrebbe quindi lavorato sul database di sviluppo fino al completamento del nuovo progetto, e in quel momento le modifiche sarebbero state unite al database di produzione e tali risorse sarebbero state archiviate / sbloccate in tutti gli ambienti.

Le modifiche del lettore funzionerebbero più o meno allo stesso modo, tranne che i ruoli di database / filesystem sarebbero invertiti: funzionano sul database di produzione e tutti gli aggiornamenti vengono caricati su dev al termine.

Il blocco delle risorse può essere limitato alle proprietà in cui si desidera garantire l'assenza di conflitti: nell'esempio 1, si bloccherebbe ID 123456non appena il giocatore inizia a crearlo, quindi agli sviluppatori non verrà assegnato quell'ID. Nell'esempio 2 i tuoi sviluppatori avrebbero bloccato il nome dello scriptassignFrenchAccent durante lo sviluppo, quindi il giocatore avrebbe dovuto scegliere un nome diverso durante lo sviluppo della sua modifica (quel piccolo fastidio può essere ridotto con lo spazio dei nomi, ma che da solo non eviterà conflitti a meno che tu non dia utente / sviluppatore di uno spazio dei nomi specifico, quindi avrai lo stesso problema con la gestione degli spazi dei nomi). Ciò significa che tutto lo sviluppo dovrebbe leggere da un singolo database online, ma in questi esempi tutto ciò di cui hai bisogno da quel database sono i nomi degli oggetti, quindi le prestazioni non dovrebbero essere un problema.

In termini di implementazione, avere una sola tabella con tutte le chiavi e lo stato delle risorse (disponibile, bloccato da dev, bloccato da prod) sincronizzato / accessibile in tempo reale tra gli ambienti dovrebbe essere sufficiente. Una soluzione più complessa implementerebbe un sistema di controllo versione completo: puoi usare un sistema esistente come CVS o SVN se le tue risorse sono tutte in un filesystem.


Di solito non è pratico bloccare tutti i dati a livello globale: i giocatori potrebbero modificare il mondo solo attraverso il gioco normale e non vorrai che il gioco impedisca ai designer di lavorare. Se si consentono i blocchi globali, un'operazione di unione è fondamentalmente un'operazione di sovrascrittura, che è facile - ma se non si dispone di blocchi globali, che cosa succede?
Kylotan,

Come menzionato da lathomas64, la risposta dipende dal tipo di dati di cui stai parlando. Senza i blocchi globali penserei che dovresti avere un sistema di controllo delle versioni e un insieme di regole per risolvere eventuali conflitti: queste regole dipenderebbero dai requisiti di dati e di gioco. Una volta che hai quelle, immagino che ogni unione si riduca a una semplice operazione di sovrascrittura.
SkimFlux,

0

Penso che il punto qui sia accettare chiaramente la tua responsabilità. 1) Il server dice ciò che è attualmente accettabile e l'API con cui accedere. Il database è in fase di modifica, secondo alcune regole. 2) I creatori possono creare contenuti, ma devono essere riproducibili dopo gli aggiornamenti. Questa è puramente una tua responsabilità: qualsiasi aggiornamento deve essere in grado di analizzare le vecchie strutture di dati preferibilmente il più semplice e pulito possibile.

L'idea del mount point ha dei vantaggi se sei interessato a tenere traccia di oggetti e posizioni unici all'interno di una struttura malleabile, specialmente se accettiamo che l'intera struttura "domestica" di un giocatore subirà un cambiamento drammatico, e vuoi mantenerlo piccoli oggetti decorativi nei rispettivi armadietti.

È un problema enormemente complicato, buona fortuna! Probabilmente non esiste una risposta.


0

Non penso che questo abbia un grosso problema mentre lo stai facendo.

Vorrei solo sovrascrivere le mod create dall'utente, con un avvertimento in cui si noti che "Mod X potrebbe non funzionare correttamente con questa versione", lasciando ai creatori di mod il compito di cambiare il loro lavoro. Non penso che questa sia un'aspettativa non realistica che gli aggiornamenti potrebbero disabilitare alcune mod.

Lo stesso vale per i contenuti creati dall'utente, basta fare un backup e sovrascrivere.

Non ho esperienza reale in questo, sto solo dando suggerimenti.


Penso che se fosse puramente per le mod fornite dall'utente, allora avresti ragione. Ma alcuni giochi riguardano esplicitamente il contenuto creato dall'utente, quindi non puoi semplicemente distruggerlo.
Kylotan,

Quindi lascia spazio nel sistema per i contenuti che potresti aggiungere in seguito. Se si utilizzano numeri ID, riservare 1-1000. Oppure, se gli utenti possono nominare le proprie risorse, non consentire agli utenti di iniziare il nome con "FINAL-" o qualcosa del genere (riservalo per le tue risorse). EDIT: o meglio ancora, fallo al contrario, forzando il contenuto dell'utente in un intervallo o in un prefisso
Woody Zantzinger,
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.