Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 | Suche | FAQ

Hauptmenü
myCSharp.de
» Startseite
» Forum
» Suche
» Regeln
» Wie poste ich richtig?

Mitglieder
» Liste / Suche
» Wer ist online?

Ressourcen
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Microsoft Docs

Team
» Kontakt
» Cookies
» Spenden
» Datenschutz
» Impressum

  • »
  • Community
  • |
  • Diskussionsforum
Effiziente(re)s Speichern von Gaming Maps und -Ständen

Moderationshinweis von Abt (13.12.2017 - 11:59)

Abgetrennt von Space Opera (C#, XNA)

Bradley
myCSharp.de - Member



Dabei seit:
Beiträge: 153

Themenstarter:

beantworten | zitieren | melden

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.
Dieser Beitrag wurde 3 mal editiert, zum letzten Mal von Bradley am .
Attachments
private Nachricht | Beiträge des Benutzers
bredator
myCSharp.de - Member



Dabei seit:
Beiträge: 357

beantworten | zitieren | melden

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.
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von bredator am .
private Nachricht | Beiträge des Benutzers
Bradley
myCSharp.de - Member



Dabei seit:
Beiträge: 153

Themenstarter:

beantworten | zitieren | melden

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.
=)
private Nachricht | Beiträge des Benutzers
bredator
myCSharp.de - Member



Dabei seit:
Beiträge: 357

beantworten | zitieren | melden

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.
private Nachricht | Beiträge des Benutzers
Bradley
myCSharp.de - Member



Dabei seit:
Beiträge: 153

Themenstarter:

beantworten | zitieren | melden

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; }
    }
private Nachricht | Beiträge des Benutzers
Taipi88
myCSharp.de - Member

Avatar #avatar-3220.jpg


Dabei seit:
Beiträge: 1.029
Herkunft: Mainz

beantworten | zitieren | melden

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
private Nachricht | Beiträge des Benutzers
Abt
myCSharp.de - Team

Avatar #avatar-4119.png


Dabei seit:
Beiträge: 16.030

beantworten | zitieren | melden

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

Aber natürlich sind die Ausgangswerte schon riesig.
private Nachricht | Beiträge des Benutzers
Bradley
myCSharp.de - Member



Dabei seit:
Beiträge: 153

Themenstarter:

beantworten | zitieren | melden

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 ?
private Nachricht | Beiträge des Benutzers
WarLorD_XaN
myCSharp.de - Member



Dabei seit:
Beiträge: 111
Herkunft: Austria

beantworten | zitieren | melden

Hi Bradley,

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

lg
private Nachricht | Beiträge des Benutzers
Khalid
myCSharp.de - Experte

Avatar #avatar-2534.gif


Dabei seit:
Beiträge: 3.511
Herkunft: Hannover

beantworten | zitieren | melden

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)
private Nachricht | Beiträge des Benutzers
Taipi88
myCSharp.de - Member

Avatar #avatar-3220.jpg


Dabei seit:
Beiträge: 1.029
Herkunft: Mainz

beantworten | zitieren | melden

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; }
    }
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von Taipi88 am .
private Nachricht | Beiträge des Benutzers
dannoe
myCSharp.de - Member



Dabei seit:
Beiträge: 225

beantworten | zitieren | melden

Zitat von Bradley
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
private Nachricht | Beiträge des Benutzers
MrSparkle
myCSharp.de - Team

Avatar #avatar-2159.gif


Dabei seit:
Beiträge: 5.655
Herkunft: Leipzig

beantworten | zitieren | melden

Zitat von Khalid
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
private Nachricht | Beiträge des Benutzers
Bradley
myCSharp.de - Member



Dabei seit:
Beiträge: 153

Themenstarter:

beantworten | zitieren | melden

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.
Attachments
private Nachricht | Beiträge des Benutzers
Deaktiviertes Profil
myCSharp.de - Member



Dabei seit:
Beiträge: 985

beantworten | zitieren | melden

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
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von Deaktiviertes Profil am .
private Nachricht | Beiträge des Benutzers
MrSparkle
myCSharp.de - Team

Avatar #avatar-2159.gif


Dabei seit:
Beiträge: 5.655
Herkunft: Leipzig

beantworten | zitieren | melden

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
private Nachricht | Beiträge des Benutzers
Taipi88
myCSharp.de - Member

Avatar #avatar-3220.jpg


Dabei seit:
Beiträge: 1.029
Herkunft: Mainz

beantworten | zitieren | melden

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
private Nachricht | Beiträge des Benutzers
jogibear9988
myCSharp.de - Member



Dabei seit:
Beiträge: 626
Herkunft: Offenau

beantworten | zitieren | melden

Schau dir für die Serializierung mal Ptotobuf, Zeroformater oder Msgpack an!
cSharp Projekte : https://github.com/jogibear9988
private Nachricht | Beiträge des Benutzers
Bradley
myCSharp.de - Member



Dabei seit:
Beiträge: 153

Themenstarter:

beantworten | zitieren | melden

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

Also Zeroformater sieht schon mal sehr interresant aus.
Damit werde ich mich weiter beschäftigen.
Erstmal Danke für die Hilfe.
private Nachricht | Beiträge des Benutzers
Bradley
myCSharp.de - Member



Dabei seit:
Beiträge: 153

Themenstarter:

beantworten | zitieren | melden

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.
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von Bradley am .
private Nachricht | Beiträge des Benutzers
Abt
myCSharp.de - Team

Avatar #avatar-4119.png


Dabei seit:
Beiträge: 16.030

beantworten | zitieren | melden

Das ist ehrlich gesagt trotzdem riesig ;-)
private Nachricht | Beiträge des Benutzers