Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

1

06.10.2015, 21:53

Spiel stürzt ab, wenn Kommentare in der XML-File eingebaut werden (C++, Boost)

Hallo zusammen,

um Mehrsprachigkeit in meinem Spiel zu unterstützen wollte ich alle Strings in XML-Files auslagern und je nach Sprache dann die entsprechenden Strings laden. Seltsamerweise stürzt das Spiel aber beim Laden ab, wenn ich in meine XML-File Kommentare einbaue. Woran könnte das liegen?

Hier mein Code:

Headerdatei des String-Loaders:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#ifndef STRINGCONTAINER_HPP
#define STRINGCONTAINER_HPP


#include "singleton.hpp"
#include <string>
#include <map>
#include <iostream>
#include <boost/property_tree/xml_parser.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/foreach.hpp>


using namespace boost::property_tree;
using namespace std;



#pragma region Sections

const int NUMBER_OF_SECTIONS = 2;

const int BUILDING = 0;
const int CHARACTER = 1;

#pragma endregion



#pragma region BuildingStrings

const int STRING_IRONPICKAXE = 0;
const int STRING_IRONSWORD = 1;
const int STRING_WOODSTAFF = 2;

#pragma endregion


#pragma region CharacterInfo

const int STRING_HEALTH = 0;
const int STRING_MANA = 1;

#pragma endregion


//the class for loading all strings
#define g_pStringContainer CStringContainer::Get()
class CStringContainer : public TSingleton<CStringContainer>
{
public:

    void LoadStrings();

    map<int, string> m_Strings[NUMBER_OF_SECTIONS];
};



#endif



Quelldatei des String-Loaders:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include "StringContainer.hpp"



void CStringContainer::LoadStrings()
{
    // populate tree structure pt
    using boost::property_tree::ptree;
    ptree pt;
    read_xml("Data/Xml/TextFileGerman.xml", pt);

    int section_counter = 0;


    BOOST_FOREACH(ptree::value_type const& v, pt.get_child("stringtable"))
    {

        BOOST_FOREACH(ptree::value_type const& w, v.second)
        {
            m_Strings[section_counter][w.second.get("<xmlattr>.ID", 0)] = w.second.get<std::string>("<xmlattr>.value");
        }

        section_counter++;
    }
    
    pt.clear();
}



XML-File:

Quellcode

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?xml version="1.0" encoding="utf-8"?>

<stringtable>
  
  <section>
    <string value ="Spitzhacke (Eisen)" ID="0"/>
    <string value ="Eisenschwert" ID="1"/>
    <string value ="Holzstab" ID="2"/>
  </section>
  
  <section>
    <string value="Leben" ID="0"/>
    <string value="Mana" ID="1"/>
  </section>
  
</stringtable>



Zur Erklärung: Alle anderen Klassen holen sich die Strings von der String-Loader Klasse. Diese hat mehrere Maps für die unterschiedlichen String-Kategorien (z.B. Strings im Baumenü, Strings in der Characterinfo). Der Zugriff auf
die Strings erfolgt dann folgendermaßen: m_Strings[KATEGORIE][ID]
Also konkret z.B. m_Strings[BUILDING][STRING_IRONPICKAXE]

Das funktioniert auch soweit. Wenn ich jetzt Kommentare einbaue, oder z.B. <section> ein Attribut "name" verpasse, stürzt das ganze beim Laden der Strings ab.
Hoffe ihr könnt mir weiterhelfen.

mfg superolelli

2

06.10.2015, 22:01

Kommentare sind auch XML-Elemente, die vom Parser an dein Programm weitergegeben werden. Ich habe noch nichts dieser XML-Bibliothek gemacht, ich bin mir aber aus anderen Bibliotheken sicher, dass auch deine eine Prüfung unterstützt, mit der man den Typ eines Elementes prüfen kann. (Bei libxml++ geht das z.B. mit dynamic_cast)

3

06.10.2015, 22:22

Es stürzt sicher nicht ohne irgendeine Meldung ab. Bemühe am besten mal den Debugger und gucke was genau passiert ;)
Noch ein paar Tips:
- verwende std::vector/list statt eines arrays.
- warum ist diese klasse ein singleton?
- pack alle includes die header noch nicht gebraucht werden in die cpp, da sonst unnötig Ballast in andere header rumgeschleppt wird.
- using im header ist zu vermeiden. Namensräume sind nicht umsonst da ;)

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »Roflo« (06.10.2015, 22:29)


4

06.10.2015, 23:40

Danke euch beiden für die Antwort :)

@ChrisvA: Ja das könnte das Problem sein. Hab den Debugger durchlaufen lassen und der hat gezeigt, dass versucht wurde auf Elemente außerhalb des Bereichs des Arrays zuzugreifen, d.h. section_count wurde hochgezählt, obwohl eigentlich keine Sektion da war (die Kommentare wurden mitgezählt)

@Roflo: Danke für die Tipps :) Mein Code läuft zwar in den meisten Fällen, aber schön ist er wahrscheinlich noch nicht. Bin da noch auf dem Weg von funktionierenden Code zu schönem Code und da sind solche Tipps sehr hilfreich.
- Warum genau? Damit ich nicht festlegen muss, wie groß das Array sein soll? Ist wahrscheinlich fehlerunanfälliger, oder?
- Ein Singleton, damit jede Klasse, die Strings benötigt ohne große Probleme darauf zugreifen kann. Und ich brauch von der Klasse auch nur eine Instanz. (Ich les grad ein Buch, in dem der Autor von der ständigen
Benutzung von Singletons abrät, weil diese die Entkopplung erschweren und halt global sind. Ist schwer aus alten Mustern rauszukommen, wenn man mal in sie verfallen ist.)
- Da hab ich noch nie dran gedacht, macht aber Sinn :)
- Ja, da hat die Faulheit zugeschlagen. Ich versuche mich zu bessern :D

BlueCobold

Community-Fossil

Beiträge: 10 738

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

5

07.10.2015, 06:36

Ein Singleton, damit jede Klasse, die Strings benötigt ohne große Probleme darauf zugreifen kann.
Genau dafür sind Singletons aber überhaupt gar nicht gedacht. Wenn Du soetwas willst, nimm eine globale Variable. Das ist auch keine schöne Lösung, aber wenigstens genau dafür da.

Ich würde Dir übrigens auch raten den section_counter abzuschaffen. Du hast ja schon selbst gemerkt, dass der Code da nur dann funktioniert, wenn Dein XML-Dokument genau so gestrickt ist, wie Dein Code. Das ist natürlich nicht der Sinn von XMLs. Die sind ja gedacht, damit man sie ändern kann ohne das Programm neu kompilieren zu müssen. Ein Ansatz wäre entweder gar keine Sections zu verwenden, weil sie scheinbar keinen echten Zweck erfüllen. Oder Du gibst die Section-ID als Attribut im XML mit - das ist allerdings gefährlich, denn wenn man sich vertut, hast Du plötzlich wieder Crashes, weil auf ungültige Indices zugegriffen wird. Hinzufügen von neuen Strings im XML ist wegen den internen Arrays ohne Anpassung des Codes ebenfalls nicht möglich, das ist also auch keine schöne Lösung. Hier würde es wohl helfen statt einem Array mit Index-Zugriff über die ID eine Map zu verwenden, bei der die ID der Schlüssel ist. Damit kannst Du dynamisch jede ID hinzufügen, die Du brauchst.
Teamleiter von Rickety Racquet (ehemals das "Foren-Projekt") und von Marble Theory

Willkommen auf SPPRO, auch dir wird man zu Unity oder zur Unreal-Engine raten, ganz bestimmt.[/Sarkasmus]

Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von »BlueCobold« (07.10.2015, 06:45)


6

07.10.2015, 12:04

Wenn Singletons hier nicht für geeignet sind, aber eine globale Variable auch keine schöne Lösung ist, gibt es dann überhaupt eine schöne Lösung?
Wie hättet ihr eure Strings denn ausgelagert?

Mit dem section_counter hast du wohl recht. Macht das ganze nur fehleranfälliger. Ich werde den entfernen.
(Und für die einzelnen strings verwende ich schon Maps. Hab halt ein Array von Maps, für jede Section eine, d.h. neue Strings kann ich ohne Probleme hinzufügen, ohne Code ändern zu müssen.)

BlueCobold

Community-Fossil

Beiträge: 10 738

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

7

07.10.2015, 12:12

Na ja, für solche Übersetzungen gibt es eigentlich diverse Standard-Lösungen/Libs, die unterschiedliche Datei-Formate nutzen.
Beispiele:

Quellcode

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
(RCP / Eclipse)
btn_ok = OK
btn_cancel = Abbrechen
-------------
(WPF)
  <data name="btn_ok">
    <value>OK</value>
  </data>
  <data name="btn_cancel">
    <value>Abbrechen</value>
  </data>
-------------
(Android)
    <string name="btn_ok">OK</string>
    <string name="btn_cancel">Abbrechen</string>

Manche dieser Beispiele gehen über statische Klassen/Methoden, andere sind normale Instanzen, die man übergibt. Vorteil von mehreren Instanzen ist, dass man mehrere Sprach-Dateien verwenden kann, die quasi Deinen Sections "entsprechen", indem sie andere Scopes definieren.
Teamleiter von Rickety Racquet (ehemals das "Foren-Projekt") und von Marble Theory

Willkommen auf SPPRO, auch dir wird man zu Unity oder zur Unreal-Engine raten, ganz bestimmt.[/Sarkasmus]

8

07.10.2015, 15:04

Ein weiteres Problem ist grad aufgetaucht:

Ä, Ö, und Ü werden nicht richtig angezeigt. Ich habe die strings aus der XML raus gelesen, in eine map als std::string gepackt und gebe dann direkt die strings aus der map aus. An welcher Stelle gehen die Umlaute "verloren" bzw. welche dieser Stellen kommt mit den Umlauten nicht zurecht? Die XML-File oder die std::strings? Und wie kann ich das ändern?

birdfreeyahoo

Alter Hase

Beiträge: 756

Wohnort: Schorndorf

Beruf: Junior Software Engineer

  • Private Nachricht senden

9

07.10.2015, 15:22

Was wird statt dem Umlauten angezeigt?
std::string verwendet afaik keine Codierung sondern speichert einfach die Bytes die du reintust. Was das im Endeffekt ist, hängt davon ab, wie boost es liest bzw. intern speichert.
In der XML-File gehen sie nicht verloren, weil die Codierung UTF-8 ist, das sollte da funktionieren. Wie gibst du denn die Strings aus?

Sacaldur

Community-Fossil

Beiträge: 2 301

Wohnort: Berlin

Beruf: FIAE

  • Private Nachricht senden

10

07.10.2015, 15:24

An welcher Stelle diese verloren gehen? Solange hier nicht jemand eine funktionierende Glaskugel rumliegen hat, dürfte man wohl nur raten können. Wie beispielsweise gibst du die Zeichenketten aus und welche Kodierung wird dort erwartet? Welche Kodierung wird für die XML-Dateien verwendet? (Nur weil in der Datei UTF-8 steht, heißt das ja noch nicht, dass der Inhalt auch tatsächlich UTF-8 kodiert ist.)
Spieleentwickler in Berlin? (Thema in diesem Forum)
---
Es ist ja keine Schande etwas falsch zu machen, als Programmierer tu ich das täglich, [...].

Werbeanzeige