Implementierung von Textdaten und co. direkt in den Quellcode oder Klasse.



  • Hallo allerseits!

    (Thema Übersicht: Spieleentwicklung, Richtung RPG, im späteren Verlauf ein MMORLG)

    Ich dachte, ich rufe mir ein wenig Hilfe auf den Plan, und schaue ob meine Idee realisierbar ist.

    Ich hab vor einiger Zeit mir vorgenommen C++ zu lernen (in der 1. Woche). Bin derweil bei Vectors und Lists. Arrays, If statements und co. Stellen für mich keine großen Probleme dar. Im Gegenteil, ist ziemlich logisch, da ich viel mit MSSQL zutun habe (mehr als ein Jahr) und andauernd stored procedures schreibe und allgemeine PHP queries, und auch PHP im Webdesign hilft da ein wenig weiter.

    Nun jedoch ist keine eigentliche Frage diese:
    Ich weiß wie ich eine Liste mit push_backs Shops programmieren die ebenso ihren Inhalt haben, welche ebenso gekauft werden können und co.

    Nun ist es so, dass ich die "itemList" im Quellcode drin habe, würde die jedoch gerne auslagern! Sprich, eine .txt Datei in einer .pak Datei im selben Ordner, wo auch die .exe Datei sich befinden wird, aus der verschiedene Sachen ausgelesen werden sollen, wie Item Daten (Service, itemID, itemString, itemName (eher wie ein Kommentar zu handhaben), type (ob Verbrauchsgegenstand usw), Rarität, etc. Etc. Etc.), Charakter/NPC/Monster Daten (fast der selbe Aufbau), usw.
    Nun, wie sage ich meinem Client später, er solle die z. B. Main_Data.pak mit dem gesetzten Passwort (z. B. 123abc) öffnen und die Datei aus "../media/textfiles/main/itemdata.txt" lesen und diese strings initialisieren?
    Ebenso würde ich das selbe über andere Dinge wissen, wie z. B. Über den Launcher Design der sich ebenso in so einer Datei befinden soll, Map Daten mit dazugehörigen Navmeshes, Animationsdaten, Meshdaten, Texturen, etc.

    Also Text basierende und "static" Data, wie ich diese einbinden kann.

    Wäre sehr dankbar wenn mir jemand helfen kann, kann z. Z. Nichts von meinen Errungenschaften online stellen, da ich vom Tablett aus schreibe. 🙂



  • MMORPG vermochte ich zu schreiben 🙂



  • Pacheon schrieb:

    Nun, wie sage ich meinem Client später, er solle die z. B. Main_Data.pak mit dem gesetzten Passwort (z. B. 123abc) öffnen und die Datei aus "../media/textfiles/main/itemdata.txt" lesen und diese strings initialisieren?

    Vergiss das, kümmere dich später darum.
    Du brauchst es jetzt nicht, und es ist später einfach nachzurüsten, also verschwende damit erstmal keine Zeit.

    Schreib das Zeug einfach direkt ins Programm, oder lade es aus einzelnen unverschlüsselten Textfiles.

    Wobei ich dir jetzt schon sagen kann dass du zu "später" nie kommen wirst. Also wäre es doppelt und dreifach unsinnig hier jetzt Zeit zu investieren.



  • Pacheon schrieb:

    Hallo allerseits!

    Guten Morgen

    Pacheon schrieb:

    (Thema Übersicht: Spieleentwicklung, Richtung RPG, im späteren Verlauf ein MMORLG)

    . o O ( Hat wer mitgezählt? Der wievielte ist das heuer? und den wievielten haben wir heute eigentlich? )

    Pacheon schrieb:

    Ich hab vor einiger Zeit mir vorgenommen C++ zu lernen (in der 1. Woche).

    In der ersten Woche diesen Jahres?? Das ist für dich "vor einiger Zeit"?

    Pacheon schrieb:

    Bin derweil bei Vectors und Lists. Arrays, If statements und co. Stellen für mich keine großen Probleme dar. Im Gegenteil, ist ziemlich logisch, da ich viel mit MSSQL zutun habe (mehr als ein Jahr) und andauernd stored procedures schreibe und allgemeine PHP queries, und auch PHP im Webdesign hilft da ein wenig weiter.

    Ok. Mal schauen. Wie entfernst du alle ungeraden Elemente eines std::vector< int > v ? Drei Worte reichen als Erklärung. Wenns sein muss tuts auch eine (<- eine) Codezeile.

    Pacheon schrieb:

    Nun jedoch ist keine eigentliche Frage diese:
    Ich weiß wie ich eine Liste mit push_backs Shops programmieren die ebenso ihren Inhalt haben, welche ebenso gekauft werden können und co.

    Würdest du bitte das nächste Mal deine Beiträge vor dem Abschicken nochmal durchlesen. Ich zumindest hab keinen Plan, was du damit sagen willst.

    Pacheon schrieb:

    Nun ist es so, dass ich die "itemList" im Quellcode drin habe, würde die jedoch gerne auslagern! Sprich, eine .txt Datei [...] aus der verschiedene Sachen ausgelesen werden sollen, wie Item Daten (Service, itemID, itemString, itemName (eher wie ein Kommentar zu handhaben), type (ob Verbrauchsgegenstand usw), Rarität, etc. Etc. Etc.), Charakter/NPC/Monster Daten (fast der selbe Aufbau), usw.

    Ist es ok, wenn ich .pak erstmal überlese? Reichen denn fürs erste nicht einfache Textdateien?

    Pacheon schrieb:

    Nun, wie sage ich meinem Client später, er solle [...] die Datei aus "../media/textfiles/main/itemdata.txt" lesen und diese strings initialisieren?

    Indem du einen Parser für das Format deiner Daten schreibst. Streams helfen dabei.

    Pacheon schrieb:

    Ebenso würde ich das selbe über andere Dinge wissen, wie z. B. Über den Launcher Design der sich ebenso in so einer Datei befinden soll, Map Daten mit dazugehörigen Navmeshes, Animationsdaten, Meshdaten, Texturen, etc.

    Können wir uns über soetwas irgendwann unterhalten nachdem du einem Parser für Textdateien fertig hast, bitte?



  • Ach ja, also ist das hier auch ein Art "Wir wissen es besser, jemand der was lernen will gehört hier nicht hin"-Klugscheißer Forum.

    Danke für nichts. Da bleibe ich liebe auf den englischen Foren, da wird jedenfalls einem die Sachen erklärt und net nur rumgenörgelt wie es für deutsche typisch ist.

    Steckt euch die Antworten sonst wohin. Ebenso den beschissenen missplatzierten Sarkasmus.



  • Keine 5 Minuten.

    #include <iostream>
    #include <fstream>
    #include <string>
    using namespace std;

    void main ()
    {
    string STRING;
    ifstream infile;
    infile.open ("names.txt");
    while(!infile.eof)
    {
    getline(infile,STRING);
    cout<<STRING;
    }
    infile.close();
    system ("pause");
    }

    und mir wird etwas erklärt und fertig ist es. Kein unnötiges geschreibe, gehöhne, oder sonstiges.

    Eine einfache Erklärung, ist wohl dem meisten zu viel verlangt.
    Wieso muss es in sinnlosem Sarkasmus, Ironie und Dummschwätzerei ausarten?
    Ist denn dieses Land so Lernfeindlich? Oder ist einfach nur der Präfrontaler Cortex nur geschädigt? Das man einfach nicht mehr die Orthographie hat mit Menschen auf hohem Niveau zu reden/schreiben? Oder einfach nur, auf gut deutsch, ein Arschloch ist?

    Wie gesagt, danke für nichts.
    Diese Demotivationen sind genau die Ursachen warum dieses Land nicht mehr scheinen wird. Gutes Beispiel ihr User.

    "Vergiss es", "Erst dann, wenn ...". Ein einfaches erklären der logischen Prozesse kommt nicht in Frage. Wünsche euch "keinen" schönen Abend. Damit auch der letzte Gockel merkt, dass das hier nicht mit einem TABLET geschrieben wurde und demnach nicht Rücksicht genommen werden muss. So viel Hirnschmalz hätte auch vorhanden sein müssen, anstelle sich zu beschweren!



  • @Pacheon
    Hast du vielleicht auch bemerkt dass der von dir hier als "Lösung" gezeigte Code keine deiner hier gestellten Fragen beantwortet? *
    Ich würde Geld wetten dass du dort, wo du deine "Lösung" bekommen hast, eine andere Frage gestellt hast.

    * Der Code implementiert genau meinen Vorschlag "oder lade es aus einzelnen unverschlüsselten Textfiles". Dass du nicht weisst wie man das macht kann ich doch nicht riechen.

    Pacheon schrieb:

    *laber*, *rumheul*, *ausfällig werd*

    Aha.



  • Pacheon schrieb:

    Keine 5 Minuten.

    #include <iostream>
    #include <fstream>
    #include <string>
    using namespace std;

    void main ()
    {
    string STRING;
    ifstream infile;
    infile.open ("names.txt");
    while(!infile.eof)
    {
    getline(infile,STRING);
    cout<<STRING;
    }
    infile.close();
    system ("pause");
    }

    und mir wird etwas erklärt und fertig ist es. Kein unnötiges geschreibe, gehöhne, oder sonstiges

    Abgesehen davon, dass dein Code sowas von falsch und vollem schlechten Stil ist, hast du Recht.
    Im Einzelnen:
    -using namespace std -> schlechter Stil
    -void main() -> falsch, Rückgabetyp ist int, Compiler mit Warnungen würde es dir auch sagen
    -string STRING -> schlechter Stil, CAPSLOCk nur für Makros
    -infile.open -> schlechter Stil, dafür gibts Konstruktoren
    -while(!infile.eof()) -> sowas von falsch, checkt nur für EOF, nicht für andere Fehler, Loops müssen lese prüfe verarbeite sein, nicht prüfe lese verarbeite
    -infile.close() -> unnötig, passiert automatisch
    -system("pause") -> nicht portabel



  • Hallo Pacheon,

    Wenn Du Daten abspeichern und wieder lesen möchtest und das noch verschlüsselt, so ist das schon eine ganze Menge; aber in C++ lässt sich das eine gut von dem anderen trennen, so dass man Schritt für Schritt vorgehen kann.

    Ein guter Anfang ist es, die Daten in Strukturen (bzw. Klassen) zusammen zu fassen. Ein ' Item ' könnte im Prinzip so aussehen:

    struct Item
    {
        int Id;
        std::string Name; // erfordert #include <string>
        int Type;
        // u.a. Member
    };
    

    für das Schreiben und Lesen fügt man sogenannte Inserter- und Extraktor-Funktionen hinzu:

    // --   Schreiben und Lesen eines Objekts 'Item'
    std::ostream& operator<<( std::ostream& out, const Item& i ) // erfordert #include <ostream>
    {
        return out << i.Id << " " << i.Name << "; " << i.Type;  // Bem.: ';' als Ende-Kennung des Namens
    }
    std::istream& operator>>( std::istream& in, Item& i )   // erfordert #include <istream>
    {
        return getline( in >> i.Id >> std::ws, i.Name, ';' ) >> i.Type;
    }
    

    ich schreibe hier hinter den Namen ein ';', damit später beim Lesen das Ende des names erkannt wird. Du müsstest in diesem Fall garantieren, dass innerhalb des Namens kein ';'-Zeichen vorkommt.

    Damit man die Item-Objekte auch schön anlegen kann, füge ich noch Konstruktoren hinzu:

    struct Item
    {
        Item() : Id(), Name(), Type()
        {}
        Item( int id, const std::string& name, int type )
            : Id( id ), Name( name ), Type( type )
        {}
        int Id;
        std::string Name; // erfordert #include <string>
        int Type;
        // u.a.
    };
    

    und schon hast Du alles beisammen um einen kleines Demo-Programm zu schreiben:

    #include <iostream>
    #include <fstream>
    #include <string>
    
    int main()
    {
        using namespace std;
    
        {   // -- Speichern
            ofstream out( "Datei.txt", ios_base::binary );
    
            out << Item( 42, "alles klar", 3 ) << endl;
            out << Item( 43, "noch was", 1 ) << endl;
            out << Item( 44, "zum dritten", 2 ) << endl;
        }
    
        {   // -- Laden
            ifstream file( "Datei.txt", ios_base::binary );
            for( Item i; file >> i; )
                cout << "Gelesen: " << i << endl;
        }
    
        return 0;
    }
    

    Damit wäre Schritt 1 schon fertig - mehr Info zu diesem Thema gibt es auch hier im Forum z.B.:
    https://www.c-plusplus.net/forum/281529-full
    https://www.c-plusplus.net/forum/281283-full
    https://www.c-plusplus.net/forum/218581-full
    https://www.c-plusplus.net/forum/212518-full

    Soll das ganze jetzt auch verschlüsselt werden, so geht das recht elegant mit der Facette std::codecvt (Code-Converter)

    Hier mal ein kleines Beispiel mit einer sehr primitive Verschlüsselung:

    class Cody : public std::codecvt< char, char, int > // erfordert #include <locale>
    {
    public:
        explicit Cody( int code, std::size_t refs = 0 )
            : std::codecvt< char, char, int >( refs )
            , Magic( char(code) )
        {}
    
    protected:
        bool do_always_noconv() const override { return false; }
        int do_encoding() const override { return 1; }   // jedes Byte einzeln
        result do_out (state_type& state, 
            const intern_type* from, const intern_type* from_end, const intern_type*& from_next,
            extern_type* to, extern_type* to_limit, extern_type*& to_next) const override;
        result do_in ( state_type& state, 
            const extern_type* from, const extern_type* from_end, const extern_type*& from_next,
            intern_type* to, intern_type* to_limit, intern_type*& to_next) const override;
    private:
        char Magic;
    };
    
    std::codecvt_base::result Cody::do_out( state_type& /*state*/, 
        const intern_type* from, const intern_type* from_end, const intern_type*& from_next,
        extern_type* to, extern_type* to_limit, extern_type*& to_next ) const
    {
        for( ; from != from_end && to != to_limit; ++from, ++to )
            *to = *from ^ Magic; // primitiv-Verschlüsselung nur als Demo
        from_next = from;
        to_next = to;
        return codecvt_base::ok;
    }
    std::codecvt_base::result Cody::do_in( state_type& /*state*/,
        const extern_type* from, const extern_type* from_end, const extern_type*& from_next,
        intern_type* to, intern_type* to_limit, intern_type*& to_next) const
    {
        for( ; from != from_end && to != to_limit; ++from, ++to )
            *to = *from ^ Magic; // primitiv-Verschlüsselung nur als Demo
        from_next = from;
        to_next = to;
        return codecvt_base::ok;
    }
    

    das wird jetzt noch in das main-Programm mit eingehängt:

    int main()
    {
        using namespace std;
    
        {   // -- Speichern
            ofstream out( "Datei.pak", ios_base::binary );
            out.imbue( locale( out.getloc(), new Cody( 201 ) ) );
    
            out << Item( 42, "alles klar", 3 ) << endl;
            out << Item( 43, "noch was", 1 ) << endl;
            out << Item( 44, "zum dritten", 2 ) << endl;
        }
    
        {   // -- Laden
            ifstream file( "Datei.pak", ios_base::binary );
            if( !file.is_open() )
            {
                cerr << "Fehler beim Oeffenn der Datei" << endl;
                return 0;
            }
            int code;
            cout << "Bitte Code eingeben (z.B. 201): ", cin >> code;
            file.imbue( locale( file.getloc(), new Cody( code ) ) );
            for( Item i; file >> i; )
                cout << "Gelesen: " << i << endl;
            if( !file.eof() )
                cerr << "Fehler beim Lesen !!" << endl;
        }
        return 0;
    }
    

    .. und fertig

    Gruß
    Werner



  • Danke Nathan und Werner Salomon.
    Mit den Erklärungen kann ich viel anfangen.

    Die Verschlüsselungsfunktionen kann man recht flexibel ändern, nehme an.
    Ein Exempel, in so einer Datei wäre durchaus diese, das eine line von einem Item mehr als 120 columns hat, also würde dies kein Problem darstellen, nach id name type - weiteres aufzulisten?

    Meine Sammlung der ganzen Einzeldaten, nur im Item Bereich, bezieht sich derweil auf knapp uber 35.000 Einträge. Wäre da ein split der Daten ratsam?
    Bsp. Itemdata5000.txt, itemdata10000.txt, etc.? Oder würde es im Endeffekt den Prozess unnötig weiter verlangsamen beim Cachen der Daten in den Spielverlauf?
    Geht hierbei auch ein preventsystem, welch Daten erst dann geladen werden sollen (gerendert und allgemein in den Cache gesteckt), wenn man in der Reichweite dieser ist (visuelle Darstellung)?

    Danke im voraus.



  • Pacheon schrieb:

    Die Verschlüsselungsfunktionen kann man recht flexibel ändern, nehme an.

    da kannst Du einbauen, was immer Du magst.

    Pacheon schrieb:

    Ein Exempel, in so einer Datei wäre durchaus diese, das eine line von einem Item mehr als 120 columns hat, also würde dies kein Problem darstellen, nach id name type - weiteres aufzulisten?

    kein Problem! Dem einlesenden Teil des Programms ist es egal ob da Zeilenumbrüche, Tabulatoren oder nur Leerzeichen stehen. Du kannst auch zwischen den einzelnen Member noch Zeilenumbrüche einfügen.

    Pacheon schrieb:

    Meine Sammlung der ganzen Einzeldaten, nur im Item Bereich, bezieht sich derweil auf knapp uber 35.000 Einträge. Wäre da ein split der Daten ratsam?
    Bsp. Itemdata5000.txt, itemdata10000.txt, etc.?

    Also wenn ich 'columns' als Zeichen in einer Zeile interpretiere, so wäre der resultierende Datensatz ca. 120*35.000Byte=4,2MB groß. Das wäre überhaupt kein Problem. Rechnen wir mal mit weniger als 1 Sekunde pro 1MB Schreib/Lesegeschwindigkeit, dann sollte das passen. Ich unterstelle dabei, dass die Daten nur am Anfang und Ende einer 'Sitzung' von bzw. auf Platte gelesen/geschrieben werden.

    Optimiere nichts, solange Du nicht weißt, dass es zu lange dauert. Wenn es dann später ein Problem werden sollte, so kann man immer noch daran drehen. (sieh dazu auch https://www.c-plusplus.net/forum/310076-full, dort konnten wir das Lesen einer 100MB-Datei von 12s auf 1,12s drücken)

    Pacheon schrieb:

    Geht hierbei auch ein preventsystem, welch Daten erst dann geladen werden sollen (gerendert und allgemein in den Cache gesteckt), wenn man in der Reichweite dieser ist (visuelle Darstellung)?

    .. ist 'ne ganz andere Baustelle. In wie weit das nötig sein sollte, musst Du selber wissen. Der Aufwand, den man sich bei so was antut, ist nicht zu unterschätzen.
    Nur soviel: Es ist schwierig - in der gezeigten Form - eine Datei nur 'teilweise' zu lesen. D.h. es wird immer die gesamte Datei gelesen werden müssen und dann unter dem Lesen entschieden, was im Speicher verbleiben soll und was nicht.

    Gruß
    Werner


Log in to reply