Forum



Flamefire am 18.08.2013 17:20 #11699


Ich würde mich mal den asyncs annehmen und gucken ob ich da was finde bzw verbessern kann so dass die nicht mehr
auftreten. Dafür brauche ich aber noch ein paar Infos zu dem Netzwerk Protokoll.

Kann mir mal jemand zusammenfassen welche Pakete wann und mit welchen Daten geschickt werden. Also z. B. Auch wie
das Verhältnis von Spielticks (GFs?) zu Netzwerk Ticks ist und wie der Ping da reinspielt.

Hab da ein paar Ideen die funktionieren könnten...

PS: es fehlt ein Dev-Forum!

---
Github: https://github.com/Flamefire


Spike am 18.08.2013 18:50 #11700

Im Ruhestand
Komm dazu am besten einfach mal in unseren IRC channel - dort können dir sicherlich Maqs,Jh oder quixui
weiterhelfen wenn sie gerade da sind.

---



qUiXui am 18.08.2013 19:33 #11701


Wie Spike schon gesagt hat, am besten ist du kommst dazu ins IRC, da lässt sich das interaktiv (er-)klären.

Generell sind die vom Spiel verschickten Daten die Subklassen von GameMessage, die findest du in GameMessages.h - dort stehn auch mehr oder weniger hilfreiche Kommentare dazu. Die Kommandos für das eigentliche Spiel sind GameCommands (z.B. "Spieler 1 baut Holzfäller bei x,y", "Spieler 3 stellt Ware X im Lagerhaus Y auf auslagern" usw), diese werden vie GameMessage_GameCommand gruppiert verschickt.

Das Spiel läuft wie du richtig gesehn hast mit 2 unterschiedlichen Geschwindigkeiten:
1) In Gameframes (GF) wird das Spiel simuliert, die Länge dieser ist von der Spielgeschwindigkeit abhängig (Schnell sind glaub ich 30ms pro GF).
2) Benutzereingaben (GameCommands) werden in Netzwerkframes (NWF) verschickt und verarbeitet, diese werden - von der GF-Länge abhängig - in Gameframes ausgedrückt (sodass dabei ca 200ms rauskommen), das heißt jeder soundsovielte GF ist auch ein NWF.

Beide Geschwindigkeiten siehst du auch im Spiel oben, z.B. auf diesem Screenshot: http://abload.de/img/tc_door_mod5psph.png
-> Die GF-Länge beträgt 40ms, jeder 7te GF ist ein NWF.


Flamefire am 19.08.2013 17:27 #11703


Fände es sinnvoll die wichtigsten Teile hier zu besprechen  als Referenz für andere.

Wie schickt und handelt der die Anfragen und Commands? Läuft alles im selben Thread? Wie ist der Ablauf? Ist es: am
Anfang vom NWF Commands bearbeiten, dann alle Commands seit letzten NWF schicken und dann alle Ger  bearbeiten mit
Beachtung der Länge? Damit ist die Reaktionszeit 2 NWF.
Was schickt er mit? Wird eine Änderung des Pings beachtet?

Das wäre das wichtigste. Rest dann gegebenenfalls im IRC.

---
Github: https://github.com/Flamefire


Spike am 19.08.2013 18:29 #11704

Im Ruhestand
Zitat:
Fände es sinnvoll die wichtigsten Teile hier zu besprechen  als Referenz für andere.


Das stimmt, einige Fragen wurden schon häufig mehrfach beantwortet, sollte man dann aber gleich in Englisch
machen.

---



qUiXui am 19.08.2013 20:28 #11706


Eine Referenz wäre überhaupt cool, leider gibts keine. Mein Wissen erstreckt sich auch nur über das, was ich mir mittels Durcharbeiten des Codes erarbeite. Nachdem mein Interesse für Netzwerkspiele bisher enden wollend war, hab ich den Bereich auch lange Zeit komplett ignoriert - insofern sind auch meine Infos dazu lückenhaft.

Zitat von Flamefire:

Wie schickt und handelt der die Anfragen und Commands?

kA was du hier meinst

Zitat:
Läuft alles im selben Thread?

Ja, RTTR ist komplett Single-Threaded.

Zitat:

Wie ist der Ablauf? Ist es: am
Anfang vom NWF Commands bearbeiten, dann alle Commands seit letzten NWF schicken und dann alle Ger  bearbeiten mit
Beachtung der Länge? Damit ist die Reaktionszeit 2 NWF.


Der Ablauf dürfte folgender sein:
Im NWF:
- Empfangene GCs ausführen
- GameFrame ausführen
- Alles an angefallenen GCs versenden

Weiß nicht was du mit Ger meinst. Die Reaktionszeit dürfte 2 NWF sein.

Zitat:

Was schickt er mit? Wird eine Änderung des Pings beachtet?

Müsste ich nachschauen was alles mitgeschickt wird. Irgendeine Checksumme+Objektzähler auf jeden Fall.

Zum Ping weiß ich nicht genau. Der Server wartet glaub ich für jeden NWF auf eine Meldung von jedem Client, wenn er keine bekommt wird das Spiel pausiert und alle müssen auf den laggenden Spieler warten. Es werden noch irgendwelche Ping-Nachrichten hin und her geschickt, kA was da genau passiert.


Flamefire am 19.08.2013 21:20 #11707


Mist na gut, dann muss ich mich wohl komplett durcharbeiten. 1-2 Dinge sind mir schon als mögliche Probleme aufgefallen. Aber eher unwahrscheinlich.
Wer hat sich denn um den Netzwerkcode gekümmert?

Ok, es gibt ja jetzt praktisch 3 Geschwindigkeiten: "FPS", GFs, NWFs. Wie würde er denn z.B. die Position der Träger auf dem Weg handeln wenn er nur mit GFs läuft?
Läuft einfach die Hauptschleife mit den FPS durch und wenn ein GF vergangen ist, schaltet er einen "Tick" weiter? Dann kann er den Rest ja interpolieren. Allerdings wie? Hat jeder Träger etc. dann eine Info, wie "zu GF 10 ist er an Position x und in GF 20 wird er an Position y sein"?

Hab gerade diese Woche mal viel Zeit und würde das mal in Angriff nehmen wollen. Und je mehr ich da schon mitkriege, desto weniger muss ich suchen (und raten...)

Die Pakete werde ich wohl mal auflisten und dokumentieren. Zumindest teilweise. Dann wäre das mal nachschlagbar. Wohin wäre das sinnvoll?

PS: Sieht man im Launchpad irgendwo, welche Branches von wo aus dem Hauptbranch zweigen und welche schon gemergt sind? (Will endlich Github!!!)

---
Github: https://github.com/Flamefire


PoC am 20.08.2013 09:39 #11713


Träger laufen völlig allein - nur commands müssen übertragen werden also: gebäude,flaggen,wege bauen, angriffe starten, optionen ändern, schiffe versenden, sachen vernichten. Sonst wird noch nen check gemacht ob der rng noch aufm selben wert is und das wars dann glaub schon.
Ping -> nwf wird ganz zu anfang 1 mal gemacht irgendwie so nwf ist am ersten gf der nach 200+max ping kommt oder so danach ist ping glaub nur noch zur show da.

Jeden frame wird geschaut ob die vergangene Zeit seit letztem gf >= gf länge ist und wenn ja gibts nen neuen gf.
Zumindest bei windows(in einem der treiber zumindest) gibts da schon probleme weil die zeit auf die weise die rttr das abfragt nur in 16ms(glaub wars) schritten gegeben wird deswegen hat man oft bei 30ms pro gf weniger als 100 gf in 3 sekunden aber bis auf bissl lag gegenüber leuten die nen andern treiber und genug fps haben aber das macht das meines wissens nach kein async sondern halt nur ganz bissl lag und das spiel bissl langsamer als gedacht auch singleplayer.

Spielercommandos(auch ai) werden in ne liste gepackt und beim nächsten nwf übertragen und ausgeführt.

Async bekommste wenn ich nix übersehn hab nur wenn bei der übertragung was nicht klappt/ausgelassen wird oder random aktionen ohne den gesyncten random gemacht werden (animationen egal).


Flamefire am 20.08.2013 18:39 #11714


Wegen der Träger zielt die Frage darauf ab, dass die ja auch voll synchron Waren transportieren müssen. D.h. bei ner gegebenen Situation ist eine bestimmte Ware immer zur gleichen "Zeit" (GF) am Ziel. Und das unabhängig von dem Spielercomputer, Lags, FPS etc. Ansonsten wird das ganze ja asynchron.
Und da die Frage, wie sowas gewährleistet wird.

---
Github: https://github.com/Flamefire


PoC am 20.08.2013 23:10 #11715


Transport/produktion/umherlaufen/auslagern und generell alles was kein Spielerkommando braucht läuft nach festen gf längen und wenn nen Zufallswert benötigt wird, z.B. wo Siedler hinlaufen wenn man ihren Weg löscht, wird aus nem synchronen generator einer geholt (hoffentlich :)).
Die leicht unterschiedlichen gf längen wegen fps/ungeauer zeit werden durch kurzes warten/lag für die schnelleren Spieler ausgeglichen beim nächsten nwf.


Marcus am 21.08.2013 10:21 #11719


Nochmal eine kurze Übersicht:

Es gibt einen EventManager, der zu festen GFs zuvor eingerichtete Events an Objekte (z.B. Träger) weitergibt. Wenn nun ein Träger loslaufen soll, so wird zunächst (auf allen Clients) der Weg berechnet und dann das erste Wegstück betreten. Hierfür wird ein Event erzeugt, dass die Callback-Funktion (obj->HandleEvent()) aufruft. In diesem Fall würde dann der Weg fortgesetzt, bis der Träger an einer Flagge ist oder es z.B. keinen Weg, kein Ziel, ... mehr gibt. An einer Flagge gäbe es dann wieder Pathfinding. In der Logik springt der Träger also zu fest definierten GFs von Punkt A zu Punkt B ohne Zwischenschritte.

Der Renderer macht sich zu nutzen, dass er die Länge dieses Sprungs kennt und interpoliert die Position, an der die Figur letztendlich dann gezeichnet wird.

Für all das ist keinerlei Interaktion über das Netzwerk notwendig. Es läuft lediglich auf jedem Rechner exakt dasselbe ab.

Waren z.B. werden alle x GF irgendwo produziert, solange die Voraussetzungen gegeben sind. Wenn eine Ware produziert ist, veranlasst dies Pathfinding für den Weg und die entsprechenden Träger werden immer dann benachrichtigt, wenn an einer sie umgebenden Flagge eine Ware aufläuft, die über ihren Weg transportiert werden muss.

Alles, was da an Zufall drin steckt, wird über einen (Pseudo-)Zufallszahlengenerator generiert, der dadurch, dass er an denselben Stellen aufgerufen wird, dieselben Werte liefert. Der Async-Check basiert neben einem Vergleich der Anzahl der Objekte und der höchsten Objekt-ID auch auf einem Vergleich des internen Wertes dieses Zufallsgenerators, mit dessen Hilfe die Zufallszahlen berechnet werden.

Wie PoC schon schreibt: lediglich das, was nicht berechenbar ist, also vom Spieler veranlasste Aktionen (Gebäude/Wege/Flaggen bauen/abreißen, Optionen umstellen, ...) wird übertragen.

Zu Asyncs kommt es nun also immer dann, wenn entweder eine solche Übertragung notwendig wäre, aber vergessen wurde, Überläufe (32-bit vs. 64-bit) auftreten, auf nicht initialisierten Speicher zugegriffen wird oder ähnliche Dinge. Das Problem mit dem Finden von Asyncs ist, dass man immer nur die Konsequenzen (Random-Wert, Objekt-ID/-Anzahl) beobachten kann, jedoch nie die Ursache.


Flamefire am 23.08.2013 18:17 #11755


Mir ist da was aufgefallen: Das "Tick"-Packet des NWF wird ignoriert.
Jeder Client berechnet den NWF Tick selbst. Wenn der eintritt wird:
1) Geguckt ob die Daten aus dem vorherigen Tick von allen Spielern da sind
2) Wenn ja GCs ausführen und aktuelle Daten senden
3) wenn nein, wird nichts gemacht.

Problem:
2 Spieler. Spieler A hat Daten von Spieler B, aber andersrum noch nicht.
Spieler A führt Tick aus und sendet Daten.
TCP garantiert AFAIR nicht die Empfangsreihenfolge. Ergo kann es passieren, dass das 2. Packet von A vor dem ersten bei B ankommt und B damit die cmds in falscher reihenfolge ausführt.
u.U. ist es also sinnvoller, Cmds nicht direkt weiterzuleiten sondern das den Server machen zu lassen. Sobald der Server alle Cmds hat, schickt er ein NWF_Done Paket mit allen Commands und der NWF ID. Das kann ja ein einziges Byte sein, da für Probleme dann 128 Pakete sich verschieben müssten. Außerdem ist TCP doch eh effektiver für größere Pakete.

---
Github: https://github.com/Flamefire


Marcus am 23.08.2013 18:52 #11757


TCP garantiert die Empfangsreihenfolge.

Über den Aufbau des Netzwerkprotokolls werde ich mir mal Gedanken machen und dann mal ein Proposal posten.


Flamefire am 23.08.2013 20:08 #11759


Ok gut, das wusste ich nicht. Dann passt das zumindest.
Hab aber grad mal noch ein paar floats/double rausgeschmissen und durch int ersetzt. Unwahrscheinlich, dass das was ausmacht aber z.b. bei der Berechnung der Verteilungen kann das sein (fMod())

---
Github: https://github.com/Flamefire




Feel free to post in English!

Antwort schreiben

Username:
Security code:
Text:

   
  Convert smilies like :), ;) etc. into small graphics?
  Convert WWW-addresses into clickable links?
  Soll Boardcode in ihrer Nachricht aktiviert werden?