Laden...

Effiziente(re)s Speichern von Gaming Maps und -Ständen

Erstellt von Bradley vor 6 Jahren Letzter Beitrag vor 6 Jahren 3.586 Views
Hinweis von Abt vor 6 Jahren

Abgetrennt von Space Opera (C#, XNA)

B
Bradley Themenstarter:in
153 Beiträge seit 2014
vor 6 Jahren

In den letzten 2 Jahren gab es einige große Umbrüche. Sowohl Privat als auch Beruflich. Letztlich habe ich aber wieder Zeit mich meinem kleinen Dauerprojekt zu widmen.

Ich bin dabei den kompletten unterbau von Space Opera neu zugestalten.
Was eigentlich einen kompletten Rebuild gleicht. Einer der Punkte ist eine möglichst offene Struktur an Daten. So möchte ich das möglichst viel an Daten und Informationen über XML gespeichert werden.

Ziel ist dabei die XML "selbstbeschreibend" zu machen, im Moment sieht das dann so aus, wobei die Startressourcen noch in eine Eigene XML wandern werden.

Das Spiel verfügt nun auch wieder über eine Speicherfunktion, wie aus vielen Spielen bekannt ist F5 Schnellspeichern und F9 Schnellladen. Dabei kam heraus das ich überraschend große Menge speichern muss. Das mag allerdings am Format von XML liegen.
So komme ich bei einer kleinen Karte auf gute 220mb (1000x1000 Felder) während eine große Karte (5000x5000 Felder) auf schlappe 3GB kommt. Wie ich diese Datenmenge kleiner bekomme muss ich mir noch gezielt überlegen.

Hier noch ein Screenshoot der aktullen Version, dabei ist zu sehen das die Karte - wie bereits ursprünglich geplant - unsichtbar ist. Danach erscheint ein "For of War".
FogOfWar

Das ganze ist noch eine sehr umfangreiche Baustelle bis ich alle Funktionen wie vom letzten Release sauber neu geschrieben habe.
Dennoch arbeiten bereits einige der neuen Funktionen soweit das ich sie Release kann.

Die Steuerung der Menus erfolgt wie gewohnt mit der Maus.
Die Steuerung des Spielers (der Blaue Platzhalterpfeil) über die Tasten W,A,S und D.
Speichern und Laden über F5 und F9

Im Spiel selbst gibt es auch eine Konsole die mit F12 geöffnet werden kann.
Bisher unterstützt die Konsole folgende Befehle:

  • add_energie:
  • add_deut:
  • add_erz:
  • add_metall:

gefolgt von einer Positiven oder Negativen Ganzzahl und einem Enter.

Was bereits Funktional Integriert ist:
Bewegung des Spielers
Laden/Speichern
Ressourcenabbau über Scannfunktion
Veredeln von Ressourcen über Raffinerrie
Grundzüge der Forschung (allerdings ohne weitere Forschungen oder Module)

Ich hoffe das ich in den nächsten Woche dazu kommen die Fehlenden Inhalte wie Forschung, Kampf, Sound und Bauen integrieren kann damit die Version 0.10 nicht lange eine Preview bleibt.

Der Download der Preview zur Version 0.10 ist in folgenden Blogeintrag ganz unten enthalten.

Über Kritik und Anregungen, als Kommentar oder Mail, würde ich mich freuen.

[Space Opera Blog](http://bradley-software.blogspot.com/)
[Space Opera Forum](http://forum.bradley-labs.de/)
B
357 Beiträge seit 2010
vor 6 Jahren

Der Nachteil von großen Datenmengen in XML halt der recht große Overhead, den XML erzeugt. Nun kann man sich entweder für platzsparendere Formate wie JSON entscheiden, oder aber man komprimiert die XML-Daten bzw. prüft diese auf Redundanzen und ob man diese auflösen kann.

Ich habe mich bei einem ähnlichen Projekt damals dafür entschieden, die Daten zu komprimieren. Libraries für 7z gibt es und die Komprimierung ist gerade bei XML (dank Wörterbüchern) enorm gut. Bei meinem Projekt war es nur noch 1/20 der ursprünglichen Größe, was bei den beschriebenen 3 GB zwar immer noch 150 MB wären, aber schonmal ein Anfang. Berücksichtigen muss man allerdings, dass das Packen und Entpacken relativ lange dauert bei entsprechenden Datenmengen.

Allerdings speicherst du bei den 5.000x5.000 Feldern knapp 120 kb an Daten pro Feld, was mir schon relativ viel vorkommt. Zudem scheint der Speicherbedarf nicht linear zu wachsen, da es bei 1000x1000 Feldern "nur" 22kb pro Feld sind. Da ist also vermutlich noch viel Verbesserungspotential vorhanden 😉

Ansonsten gefällt mir das Projekt nach wie vor recht gut. Ich mag die Art von Spielen.

B
Bradley Themenstarter:in
153 Beiträge seit 2014
vor 6 Jahren

Grad mal nachgeschlagen, nicht nur das JSON 'Kleiner' ist, es kann auch Arrays.
Die Map ist ja nix anderes als ein Array aus Klassen, um das in XML zu de/serialisieren musste ich immer den umweg gehen das in eine Liste umzuwandeln.

Würde damit 2 Fliegen erschlagen, Code verschlanken und dann noch kleinere Datei erzeugen.

[Space Opera Blog](http://bradley-software.blogspot.com/)
[Space Opera Forum](http://forum.bradley-labs.de/)
B
357 Beiträge seit 2010
vor 6 Jahren

Korrektur (danke für die Info, herbivore): Der Speicherbedarf sinkt mit der Spielfeldgröße und es sind bei der 1000-Feld-Variante 220 Byte pro Feld.

Ich sollte es mir abgewöhnen vor dem ersten Kaffee Dinge zu tippen und schon gleich gar nicht, wenn ich nebenbei noch an anderen Sachen rumwurstel (da hab ich auch einen Fehler reingehauen).

Das Overhead-Problem ist davon natürlich nicht betroffen.

B
Bradley Themenstarter:in
153 Beiträge seit 2014
vor 6 Jahren

Hab mal eine kleine Testreihe gemacht, XML vs. JSON.

Kleine Karte (1000x1000): 312 mb | 116 mb
Mittlere Karte (2500x2500): 1.967 mb | 744 mb
Große Karte (5000x5000): 7.900 mb | 3.000 mb

Dieser Klasse wird pro Feld Serialisiert.

    public class mapField
    {
        public Int64 ID { get; set; }
        public int Maplevel { get; set; }
        public Vector2 Koordinaten { get; set; }
        public SpaceFieldTypes FeldTyp { get; set; }
        public SpaceFieldTypes FeldTypOrigin { get; set; }
        public int RessourceResetCounter { get; set; }
        public SpaceFieldVisble Visible { get; set; }
    }
[Space Opera Blog](http://bradley-software.blogspot.com/)
[Space Opera Forum](http://forum.bradley-labs.de/)
1.029 Beiträge seit 2010
vor 6 Jahren

Hi,

also das wäre für mich nicht wirklich gut - da wirst du definitiv optimieren müssen.

Die ID ist doch sicher eine fortlaufende Nummer? -> weglassen, beim Laden einfach der Reihenfolge nach durchnummerieren.

MapLevel lässt sich möglicherweise aus der Gesamtzahl der Records berechnen?
Koordinaten sicher genauso.

Feldtypen musst du wohl speichern, RessourceResetCounter hat sicher irgendwie einen Standardwert - dann würde ich das Feld nur speichern, wenn es von diesem Standartwert abweicht, etc.

LG

16.806 Beiträge seit 2008
vor 6 Jahren

Das Json kann man sicherlich mit wenig Aufwand komprimieren (GZip).

Aber natürlich sind die Ausgangswerte schon riesig.

B
Bradley Themenstarter:in
153 Beiträge seit 2014
vor 6 Jahren

Stimmt schon was du sagst.
ID kann raus.
Maplevel ebenso -> überbleibsel einer Idee die ich verworfen habe
Koordinaten brauch ich ingame.

Mit dem Resetcounter bringst du mich da tatsächlich auf einen Gedanken.
Nur wie kann ich steuern ob das Feld Serialisiert wird wenn es nicht den Standartwert von 0 hat ?

[Space Opera Blog](http://bradley-software.blogspot.com/)
[Space Opera Forum](http://forum.bradley-labs.de/)
W
113 Beiträge seit 2006
vor 6 Jahren

Hi Bradley,

wäre für solche Daten nicht ein Binärformat (TLV, oder was eigenes) sinnvoller?

lg

3.511 Beiträge seit 2005
vor 6 Jahren

Heutige Spiele mit solch großen Karten werden meist prozedural erstellt und nur der Hash wird gespeichert (oder andere ähnliche Algorithmen). So, dass man vom Hash aus wieder auf die generierte Karte kommt. Anschließend müssen nur die Veränderungen gespeichert werden (das was Tapi88 schon geschrieben hat). So macht es z.B. auch Stellaris. Da ist ein Savegame nur wenige MB groß bei gigantischen Karten.

"Jedes Ding hat drei Seiten, eine positive, eine negative und eine komische." (Karl Valentin)

1.029 Beiträge seit 2010
vor 6 Jahren

Hi,

ja sicher brauchst du die Koordinaten ingame - aber - solang die Einträge in der richtigen Reihenfolge sind kannst du die Koordinaten doch einfach beim laden berechnen. Viel sinnvoller wie 5000x5000x2 Integer-Werte in Text-Repräsentation mit Bezeichner jeweils vornedran zu speichern...

Ähnliches gilt halt auch für den ResourceResetCounter - als Beispiel: Der Standardwert ist ggf. 10 - aber du speicherst das Property nur, wenn der Wert von 10 abweicht - beim Laden weist du ja automatisch, was da reingehört.

Die Abspeicherung im Binärformat würde ich definitiv auch empfehlen - rumeditieren von Hand will in einer solch langen Datei ohnehin niemand 😉

Edit:
Nach als Beispiel für Json.Net (falls du das wirklich willst), dass du z.B. nur Werte die vom Standard abweichen speicherst - beim Einlesen aber direkt befüllst oder halt komplett rauslässt:


public class MapField
    {
        [JsonIgnore]
        public long ID { get; set; }
        [JsonIgnore]
        public int Maplevel { get; set; }
        [JsonIgnore]
        public Vector2 Koordinaten { get; set; }
        public SpaceFieldTypes FeldTyp { get; set; }
        public SpaceFieldTypes FeldTypOrigin { get; set; }
        [DefaultValue(8)]
        [JsonProperty(DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate)]
        public int RessourceResetCounter { get; set; }
        public SpaceFieldVisble Visible { get; set; }
    }

D
261 Beiträge seit 2015
vor 6 Jahren

Nur wie kann ich steuern ob das Feld Serialisiert wird wenn es nicht den Standartwert von 0 hat ?

Falls du JSON.NET verwendest: Conditional Property Serialization

5.657 Beiträge seit 2006
vor 6 Jahren

Heutige Spiele mit solch großen Karten werden meist prozedural erstellt und nur der Hash wird gespeichert (oder andere ähnliche Algorithmen). So, dass man vom Hash aus wieder auf die generierte Karte kommt.

Diese Herangehensweise würde ich auch empfehlen. So kann man selbst "Endlos"-Maps mit nur wenigen Bytes speichern und laden. Hier wurde das auch schonmal etwas ausführlicher diskutiert: Zufallsgenerierte endlose 2D Map: Erst oben dann links != Erst nach links & dann nach oben

Weeks of programming can save you hours of planning

B
Bradley Themenstarter:in
153 Beiträge seit 2014
vor 6 Jahren

Ich denke mal das Speichern in Binärform ist für die Map tatsächlich sinnvoll.
Leider stoße ich hier an technischen beschränkungen schon bei der mittleren Map.

Bis ich da eine brauchbare lösung habe, reduziere ich den Inhalt der mapfield - Klasse und speichere es als JSON.

[Space Opera Blog](http://bradley-software.blogspot.com/)
[Space Opera Forum](http://forum.bradley-labs.de/)
D
985 Beiträge seit 2014
vor 6 Jahren

Und dieser Fehler soll uns jetzt was sagen?

Es wäre sehr hilfreich, wenn du die entsprechende Code-Stelle zeigen würdest, die diesen Fehler produziert, dann kann man auch etwas dazu sagen.

Bislang bleibt nur: „Oh, du hast da eine Exception beim Serialisieren!“

PS Ich habe zwar eine Vermutung, aber das wäre nur ein Schuss in die Nebelwand

5.657 Beiträge seit 2006
vor 6 Jahren

Die Fehlermeldung ist ja ziemlich eindeutig 😉

Aber wenn dazu noch Fragen offen sind, solltest du einen neuen Thread im passenden Unterforum aufmachen.

Weeks of programming can save you hours of planning

1.029 Beiträge seit 2010
vor 6 Jahren

Hi,

der BinaryFormatter kann soweit ich weiß nur bis ca. 6 Mio Items serialisieren - den hat hier allerdings auch niemand empfohlen, da du etliche Features vom Formatter gar nicht brauchst.

Ich bin mir recht sicher mit etwas Einarbeitung arbeitest du etwas deutlich geeigneteres aus.

LG

J
641 Beiträge seit 2007
vor 6 Jahren

Schau dir für die Serializierung mal Ptotobuf, Zeroformater oder Msgpack an!

cSharp Projekte : https://github.com/jogibear9988

B
Bradley Themenstarter:in
153 Beiträge seit 2014
vor 6 Jahren

Hätte Abt mir noch mitgeteilt das er das Thema getrennt hätte, hätte ich auch noch hier drauf geantwortet 😄

Also Zeroformater sieht schon mal sehr interresant aus.
Damit werde ich mich weiter beschäftigen.
Erstmal Danke für die Hilfe.

[Space Opera Blog](http://bradley-software.blogspot.com/)
[Space Opera Forum](http://forum.bradley-labs.de/)
B
Bradley Themenstarter:in
153 Beiträge seit 2014
vor 6 Jahren

Nachdem ich jetzt ein wenig Zeit hatte, habe ich mit dem ganzen ein wenig herum gespielt.
Das wechseln von XML zu JSON hat schon mal gut 2/3 weniger Speicherbedarf gebracht.

Kleine Karte von 300 auf rund 100mb.

Jetzt noch ein paar Prüfungen rein wie von @dannoe empfohlen und ich bin von 100mb auf 10mb herunter. Die große Karte ist von rund 3GB auf rund 250 mb geschrumpft.

[Space Opera Blog](http://bradley-software.blogspot.com/)
[Space Opera Forum](http://forum.bradley-labs.de/)
16.806 Beiträge seit 2008
vor 6 Jahren

Das ist ehrlich gesagt trotzdem riesig 😉