Bei den Pixonic DevGAMM Talks sprach auch unser DTO Anton Grigoriev. Wir von der Firma haben bereits gesagt, dass wir an einem neuen PvP-Shooter arbeiten, und Anton teilte einige der Nuancen der Architektur dieses Projekts. Er erklärte, wie die Entwicklung so aufgebaut werden kann, dass Änderungen in der Spielelogik des Clients automatisch auf dem Server angezeigt werden (und umgekehrt) und ob es möglich ist, keinen Code zu schreiben, sondern den Datenverkehr zu minimieren. Unten finden Sie eine Aufzeichnung und eine Abschrift des Berichts.
Ich werde nicht lernen, wie man etwas macht, ich werde darüber sprechen, wie wir es gemacht haben. Damit Sie nicht auf den gleichen Rechen treten und unsere Erfahrung nutzen können. Vor anderthalb Jahren wussten wir im Unternehmen nicht, wie man Schützen auf Mobiltelefonen herstellt. Sie sagen, wie es ist, Sie haben Kriegsroboter, 100 Millionen Downloads, 1,5 Millionen DAUs. Aber in diesem Spiel sind Roboter sehr langsam, und wir wollten einen schnellen Schützen machen, und die Architektur von War Robots erlaubte dies nicht.
Wir wussten wie und was zu tun war, aber wir hatten keine Erfahrung. Dann haben wir eine Person eingestellt, die diese Erfahrung gemacht hat und gesagt hat: Machen Sie dasselbe, was Sie bereits hundert Mal getan haben, nur besser. Dann setzten sie sich und begannen ĂĽber Architektur nachzudenken.

Kam zum Entity Component System (ECS). Ich denke, viele Leute wissen, was es ist. Alle Objekte der Welt werden durch Entitäten dargestellt. Zum Beispiel ein Spieler, seine Waffe, ein Objekt auf der Karte. Sie haben Eigenschaften, die durch Komponenten beschrieben werden. Beispielsweise ist die Transformationskomponente die Position des Spielers im Raum und die Gesundheitskomponente seine Gesundheit. Es gibt Logik - sie ist getrennt und wird durch Systeme dargestellt. Typischerweise sind Systeme die Execute () -Methode, die Komponenten eines bestimmten Typs durchläuft und mit ihnen etwas mit der Spielwelt macht. Zum Beispiel durchläuft MoveSystem alle Bewegungskomponenten, betrachtet die Geschwindigkeit in dieser Komponente, den Parameter und berechnet auf dieser Grundlage die neue Position des Objekts, d. H. schreibt es an Transform.
Eine solche Architektur hat ihre eigenen Eigenschaften. Bei der Entwicklung auf ECS mĂĽssen Sie anders denken und Dinge tun. Einer der Pluspunkte ist eher die Zusammensetzung als die Mehrfachvererbung. Erinnern Sie sich an diese Raute mit Mehrfachvererbung in C ++? Alle seine Probleme. Dies ist bei ECS nicht der Fall.

Das zweite Merkmal ist die Trennung von Logik und Daten, über die ich bereits gesprochen habe. Was gibt uns das? Wir können den Zustand der Welt und ihre Geschichte in Stapeln speichern, wir können sie serialisieren, wir können diese Daten über das Netzwerk senden und sie in Echtzeit ändern. Dies sind nur Daten im Speicher - wir können jeden Wert jederzeit ändern. Daher ist es sehr praktisch, die Logik des Spiels zu ändern (oder zu debuggen).
Es ist auch sehr wichtig, die Reihenfolge der Systemaufrufe zu verfolgen. Alle Systeme gehen nacheinander, werden von der Execute () -Methode aufgerufen und sollten im Idealfall unabhängig sein. In der Praxis passiert dies nicht. Ein System verändert etwas in der Welt, ein anderes System verwendet es dann. Und wenn wir diese Reihenfolge brechen, wird das Spiel anders laufen. Wahrscheinlich nicht viel, aber definitiv nicht das Gleiche wie zuvor.
Schließlich ist eines der wichtigsten und wichtigsten Merkmale für uns, dass wir denselben Code sowohl auf dem Client als auch auf dem Server ausführen können.
Geben Sie dem Entwickler eine Gelegenheit, und er wird 99 Wege und Gründe finden, um seine Entscheidung zu treffen, und keine vorhandenen verwenden. Ich denke, viele haben es getan. Wir haben damals nach dem ECS-Framework gesucht. Wir haben Entitas, Artemis C #, Ash.net und unsere eigene Lösung in Betracht gezogen, die aus der Erfahrung eines Spezialisten geschrieben werden konnte, der zu uns kam.

Versuchen Sie nicht zu lesen, was auf der Folie steht, es ist nicht so wichtig. Wichtig ist, wie viel Grün und Rot in den Spalten sind. Grün bedeutet, dass die Lösung die Anforderungen unterstützt, Rot - unterstützt nicht, Gelb - unterstützt, aber nicht ganz.
In der Spalte ist ECS möglicherweise unsere Lösung. Wie Sie sehen, ist es cooler - wir könnten viel mehr Anforderungen unterstützen. Infolgedessen haben wir einige von ihnen nicht unterstützt (hauptsächlich, weil sie nicht benötigt wurden), und einige, ohne die wir nicht weiter arbeiten konnten, mussten durchgeführt werden. Wir haben uns für Architektur entschieden, lange gearbeitet, eine minimal spielbare Version erstellt und ... fakap.

Es stellte sich heraus, dass die Version nicht spielbar war. Der Spieler rollte ständig zurück, bremste, der Server hing mitten im Spiel. Es war unmöglich, es zu spielen. Was waren die Gründe für die Ausfälle?
Grund Nr. 1 und das Wichtigste ist Unerfahrenheit. Aber wie so? Wir haben eine erfahrene Person eingestellt, die alles wunderbar machen sollte. Ja, aber in Wirklichkeit haben wir ihm nur einen Teil der Arbeit gegeben. Wir sagten: "Hier ist ein Spieleserver für dich, arbeite daran." Und in unserer Architektur (dazu später mehr) spielt der Kunde eine sehr wichtige Rolle. Und diesen Teil gaben wir einem Mann, der nicht die nötige Erfahrung hatte. Nein, er ist ein guter Programmierer, Senor - es gab einfach keine Erfahrung. Das heißt, Er hatte keine Ahnung, was für ein Rechen es geben könnte.
Grund Nr. 2 - unrealistische Zuweisungen. 80 KB / Frame. Ist es viel oder nicht? Wenn wir berücksichtigen, dass wir 30 Bilder pro Sekunde haben, erhalten wir in einer Sekunde 2,5 MB, und für ein 5-Minuten-Match gibt es bereits mehr als 600 MB. Kurz gesagt, viel. Der Garbage Collector versucht intensiv, all diesen Speicher freizugeben (wenn wir immer mehr von ihm verlangen), was zu Spitzen führt. Da wir 30 Bilder pro Sekunde wollten, störten uns diese Spitzen sehr. Darüber hinaus sowohl auf dem Client als auch auf dem Server.
Der Hauptgrund für die Zuweisung war, dass wir ständig Datenarrays zugewiesen haben. Fast jedes Mal jedes Bild. Verwendete LINQ-, Lambda-Ausdrücke und Photonen. Photon ist eine Netzwerkbibliothek, die wir kennen und in War Robots verwenden. Und alles scheint in Ordnung zu sein, aber es reserviert jedes Mal Speicher, wenn es Daten sendet oder empfängt.
Wenn wir die ersten Probleme behoben haben (in unsere benutzerdefinierten Sammlungen umgeschrieben, Caching durchgeführt), war mit Photon praktisch nichts zu tun, da es sich um eine Bibliothek eines Drittanbieters handelt. Es war nur möglich, die Paketgröße zu reduzieren, und wir hatten 5 KB. Viel? Ja Es gibt MTU - dies ist die minimale tatsächliche Paketgröße, die über UDP gesendet wird, ohne das Paket in kleine Teile zu zerlegen. Es ist ungefähr 1,5 KByte groß und wir hatten 5 (im Durchschnitt gab es mehr).
Dementsprechend schnitt Photon unser Paket in kleine und schickte jedes Stück als zuverlässig, d. H. mit garantierter Lieferung. Jedes Mal, wenn das Teil nicht erreichte, schickte er es immer wieder. Wir haben noch mehr Latenz und das Netzwerk hat schlecht funktioniert.
All diese Zuordnungen führten dazu, dass wir einen Frame von ungefähr 100 Millisekunden erhielten, als 33 benötigt wurden. Und dort, Rendering, Simulation und andere Aktionen - all dies benötigt die CPU. Alle diese Probleme sind komplex, d.h. es war unmöglich, eine zu entscheiden, und alles würde gut werden. Es war notwendig, sie alle auf einmal zu lösen.
Und ein weiteres kleines Problem, das während der Entwicklung auftrat - eine große Anzahl von Repositories. 5 steht auf der Folie, aber es scheint mir, dass es noch mehr davon gab. Alle diese Repositorys (für den Client, den Spieleserver, allgemeinen Code, Einstellungen und etwas anderes) wurden durch Submodule mit den beiden Hauptrepositorys für den Client und den Spielserver verbunden. Es war schwer damit zu arbeiten. Programmierer können mit Git, SVN arbeiten, aber es gibt auch Künstler, Designer usw. Ich denke, viele haben versucht, einem Künstler oder Designer beizubringen, wie man mit einem Versionskontrollsystem arbeitet. Das ist wirklich schwierig. Wenn Ihr Designer also weiß, wie es geht - kümmern Sie sich um ihn, er ist ein wertvoller Mitarbeiter. In unserem Fall sind sogar Programmierer ausgeflippt, und infolgedessen haben wir alles auf ein Repository reduziert.
Dies war eine großartige Lösung für das Problem. Wir haben dort einen Ordner mit einem Server und einen Ordner mit einem Client. Der Server besteht aus einem Spielserverprojekt, einem Codegenerator und zusätzlichen Tools.

Ein Client ist ein Unity-Client und allgemeiner Code. Ein gemeinsamer Code ist eine Weltdatenstruktur, d.h. Entitäten, Komponenten und Systemsimulation. Dieser Code wird hauptsächlich vom Servergenerator generiert. Es wird vom Server verwendet. Das heißt, Dies ist ein allgemeiner Bestandteil für Client und Server.
Leben. Wir nehmen TeamCity, stellen es in unser Repository, sammeln und stellen den Server bereit. Jedes Mal, wenn ein Client die allgemeine Logik ändert, wird hier ein Spieleserver zusammengestellt - jetzt wird kein Serverprogrammierer mehr benötigt. Normalerweise gibt es einen Server, einen Client und einige Funktionen. Der Client sieht es zu Hause, der Server zu Hause, und eines Tages wird es für sie funktionieren. In unserem Fall ist dies nicht der Fall. Der Client kann diese Funktion schreiben und alles funktioniert auf dem Server.
Das Match besteht aus einem gemeinsamen Teil (als ECS bezeichnet) und einer Präsentation (dies sind einheitliche MonoBehavior-Klassen, GameObjects, Modelle, Effekte - alles, was die Welt darstellt). Sie sind nicht verbunden.

Zwischen ihnen befinden sich Moderatoren, die mit beiden Teilen arbeiten. Wie Sie verstehen, ist dies MVP (Model-View-Presenter) und jedes dieser Teile kann bei Bedarf ersetzt werden. Es gibt einen anderen Teil, der mit dem Netzwerk funktioniert (auf der Folie - Netzwerk). Dies ist die Serialisierung von Informationen ĂĽber die Welt, die Serialisierung von Eingaben, das Senden an den Server, das Empfangen durch den Server, die Verbindung zum Server usw.
Mehr Likes. Wir nehmen und ersetzen diesen Teil durch ein Paket, das nicht real, ĂĽber das Netzwerk, sondern virtuell ist. Wir erstellen ein Objekt im Client und senden ihm Nachrichten. Es implementiert eine Serversimulation - jetzt erledigt dieses Objekt alles, was auf dem Spieleserver passiert ist. Die restlichen Spieler werden durch Bots ersetzt.

Fertig. Wir haben das Spiel und die Möglichkeit, es ohne einen Spieleserver zu testen. Was bedeutet das? Dies bedeutet, dass der Künstler, nachdem er einen neuen Effekt erstellt hat, im Editor auf die Schaltfläche „Abspielen“ klicken, sofort zum Spiel auf der Karte gelangen und sehen kann, wie es funktioniert. Oder debuggen Sie für Client-Programmierer, was sie geschrieben haben.
Wir gingen jedoch noch weiter und hingen an diese Schichtemulation des Jitter-Pings von Netzwerkverzögerungen (dies ist der Fall, wenn Pakete im Netzwerk nicht in der Reihenfolge ankommen, in der sie gesendet wurden) und anderen Netzwerksachen an. Als Ergebnis haben wir ein praktisch echtes Match ohne einen Spieleserver bekommen. Es funktioniert, überprüft.
Kommen wir zurĂĽck zur Codegenerierung.

Ich habe bereits gesagt, dass wir einen Codegenerator in einem Spieleserver haben. Es gibt eine domänenspezifische Sprache, die eigentlich eine einfache C # -Klasse ist. In diesem Fall die Klasse Gesundheit. Wir kennzeichnen es mit unseren Attributen. Beispielsweise gibt es ein Komponentenattribut. Er sagt, dass Gesundheit ein Bestandteil unserer Welt ist. Basierend auf diesem Attribut erstellt der Generator eine neue C # -Klasse, in der eine Reihe von Dingen enthalten sind. Sie können von Hand geschrieben werden, aber es wird generiert. Zum Beispiel die Methode zum Hinzufügen einer Komponente zur Entität, die Methode zum Suchen nach Komponenten, Serialisieren von Daten usw. Es gibt ein Attribut vom Typ DontSend, das besagt, dass es nicht erforderlich ist, ein Feld über das Netzwerk zu senden - der Server benötigt es nicht oder der Client benötigt es nicht. Oder das Attribut Mach, das angibt, dass der Spieler einen maximalen Gesundheitswert von tausend hat. Was gibt uns das? Anstelle eines Feldes, das 32 Bit (int) belegt, senden wir 10 Bit - dreimal weniger. Mit einem solchen Codegenerator konnten wir die Paketgröße von 5 KB auf 1 reduzieren.

1 KB <1,5 - d.h. Wir haben die MTU getroffen. Photon hörte auf zu schneiden und das Netzwerk wurde viel besser. Fast alle ihre Probleme sind verschwunden. Aber wir gingen weiter und machten eine Delta-Komprimierung.

In diesem Fall senden Sie einen vollständigen Status und dann nur dessen Änderungen. Es kommt nicht vor, dass sich die ganze Welt sofort komplett verändert hat. Nur einige Teile ändern sich ständig und diese Änderungen sind viel kleiner als der Staat selbst. Wir haben durchschnittlich 300 Bytes erhalten, d.h. 17 mal weniger als ursprünglich.
Warum ist das notwendig, wenn Sie bereits in die MTU eingestiegen sind? Das Spiel wächst ständig, neue Funktionen erscheinen und mit ihnen erscheinen Objekte, Entitäten, neue Komponenten. Die Datengröße wächst. Wenn wir bei 1 KB anhalten würden, würden wir sehr bald zum gleichen Problem zurückkehren. Nachdem wir es für die Delta-Komprimierung umgeschrieben haben, werden wir dies nicht sehr bald erreichen.
Jetzt der süßeste Teil. Synchronisieren Wenn Sie Schützen spielen, wissen Sie, was Input Lag ist - wenn Sie auf die Schaltfläche klicken und der Charakter sich nach einiger Zeit, beispielsweise einer halben Sekunde, zu bewegen beginnt. Für einige Spiele im Mob-Genre ist dies normal. Aber im Schützen soll der Held genau dort schießen und Schaden anrichten.

Warum tritt Input Lag auf? Der Client sammelt die Eingaben des Spielers (Eingaben) und sendet sie an den Spielserver (das Senden dauert einige Zeit). Dann verarbeitet der Spielserver es (wieder Zeit) und sendet das Ergebnis zurück (wieder Zeit). Dies ist eine Verzögerung. Wie entferne ich es? Es gibt eine Sache namens Vorhersage - der Client wartet nicht auf eine Antwort vom Server und versucht sofort, dasselbe zu tun wie der Spieleserver, d. H. täuscht vor. Nimmt die Spielereingabe auf und startet die Simulation. Wir simulieren nur einen lokalen Kunden, weil wir die Eingaben anderer Spieler nicht kennen - sie kommen nicht zu uns. Daher führen wir das Simulationssystem nur auf unserem Player aus.
Erstens kann die Simulationszeit verkürzt werden. Der Client startet die Simulation, sobald er die Eingabe erhält, und ist gegenüber dem Spielserver einige Schritte voraus. Nehmen wir an, er simuliert in diesem Bild Tick Nr. 20. Zu diesem Zeitpunkt simuliert der Spielserver Tick Nr. 15 in der Vergangenheit. Der Kunde sieht den Rest der Welt wieder in der Vergangenheit selbst - in der Zukunft. Während er den 20. Tick an den Server sendet, während dieser Eingang erreicht, beginnt der Spielserver bereits, den 18. Tick oder bereits den 20. zu simulieren. Wenn der 18., dann legt er es in den Puffer, erreicht den 20., verarbeitet und gibt das Ergebnis zurück.
Nehmen wir an, er simuliert jetzt Tick Nr. 15. Verarbeitet, gibt das Ergebnis an den Client zurück. Der Kunde hat eine Art simulierten 15. Tick, 15. Spielstatus und die von ihm vorhergesagte Spielwelt. Der Vergleich mit dem Server beginnt. Tatsächlich vergleicht er nicht die ganze Welt, sondern nur seinen Kunden, weil wir nicht für den Rest der Welt verantwortlich sind. Wir sind nur für uns selbst verantwortlich. Wenn der Spieler übereinstimmte, ist alles in Ordnung, was bedeutet, dass wir richtig simuliert haben, die Physik korrekt funktioniert hat und keine Kollisionen aufgetreten sind. Dann simulieren wir weiter den 20. Tick, den 21. und so weiter.
Wenn der Kunde / Spieler nicht übereinstimmte, bedeutet dies, dass wir uns irgendwo geirrt haben. Beispiel: Da die Physik nicht deterministisch ist, hat sie unsere Position nicht richtig berechnet oder etwas ist passiert. Vielleicht nur ein Fehler. Dann nimmt der Client den Status vom Spielserver, da der Spielserver ihn bereits bestätigt hat (er vertraut dem Server - wenn er nicht vertraut, würden die Spieler betrügen) und simuliert den Rest vom 15. bis zum 20. erneut. Weil dieser Zeitzweig jetzt fehlerhaft ist.
Erstellen Sie einen neuen Zeitzweig, d. H. Parallelwelten. Wir simulieren diese fĂĽnf Ticks in einem Tick. Sobald unsere Simulation 5 Millisekunden gedauert hat, aber wenn wir 10 Ticks simulieren mĂĽssen, sind es bereits 50 Millisekunden und wir fallen nicht in unsere 30 Millisekunden. Sie haben optimiert und eine Millisekunde erhalten - jetzt werden 10 Ticks in 10 Millisekunden verarbeitet. Weil es noch Rendering gibt.
All diese Dinge funktionieren beim Kunden, und wir haben sie der Person ohne die erforderliche Erfahrung gegeben. Minus - wir hatten ein Fakap und auĂźerdem - dass der Programmierer jetzt weiĂź, wie man es richtig macht.

Dieses Schema hat seine eigenen Eigenschaften. Der Klient auf dem linken Bild versucht, den Feind aufzuspüren. Er ist im 20. Tick, der Gegner im 15. Tick. Weil Ping und Client dem Server 5 Ticks voraus sind. Der Klient schießt und muss genau treffen und Schaden anrichten, vielleicht sogar einen Kopfschuss. Auf dem Server ist das Bild jedoch anders - wenn der Server beginnt, den 20. Tick zu simulieren, kann sich der Feind bereits bewegen. Zum Beispiel, wenn sich der Feind bewegte. Theoretisch sollten wir nicht bekommen. Aber wenn das so klappen würde, würde niemand aufgrund ständiger Fehler Online-Shooter spielen. Je nach Ping hat sich auch die Schlagwahrscheinlichkeit geändert: Je schlechter der Ping, desto schlechter wird es. Deshalb machen sie es anders.
Der Server nimmt und rollt die ganze Welt zu dem Teakholz, in dem der Spieler die Welt gesehen hat. Der Server weiß, wann es war, rollt es zurück zum 15. Tick und sieht das linke Bild. Er sieht, dass der Spieler hätte treffen sollen, und fügt seinem Gegner bereits im 20. Tick Schaden zu. Alles ist gut. Fast. Wenn der Feind geflohen ist und hinter ein Hindernis gerannt ist, haben wir bereits einen Kopfschuss durch die Mauer gemacht. Aber das ist ein bekanntes Problem, die Spieler wissen davon und machen sich keine Sorgen. Es funktioniert also, es gibt nichts zu tun.

Wir haben also 30 Ticks pro Sekunde und 30 Frames pro Sekunde erreicht. Jetzt spielen ungefähr 600 Spieler gleichzeitig auf unserem Server. Es gibt 6 Spieler im Spiel, d.h. ungefähr 100 Übereinstimmungen. Wir haben keinen Serverprogrammierer, wir brauchen ihn nicht. Clients schreiben die gesamte Logik im Unity-Editor Rider in C # und sie funktioniert auf einem Spieleserver. Fast immer. Wir haben die Paketgröße um das 17-fache und die Speicherzuweisungen um das 80-fache reduziert - jetzt sogar weniger als ein Kilobyte auf dem Client und dem Server. Der durchschnittliche Ping-Wert betrug 200 bis 250 ms, jetzt sind es 150. 200 ist der Standard für Spiele in Mobilfunknetzen, im Gegensatz zu einem PC, bei dem alles viel schneller abläuft, insbesondere in einem lokalen Netzwerk.

Wir planen, das, was in einem separaten Framework geschrieben ist, zu isolieren, um es für andere Projekte zu verwenden. Bisher ist jedoch nicht von Open Source die Rede. Und fügen Sie dort Interpolation hinzu. Jetzt haben wir 30 Ticks pro Sekunde, wir können zeichnen, wie es tickt. Aber es gibt Spiele, bei denen 20 Ticks pro Sekunde oder 10 ausreichen. Wenn wir also 10 Mal pro Sekunde ziehen, bewegen sich die Charaktere in Rucken. Daher ist eine Interpolation erforderlich. Wir haben unsere eigene Netzwerkbibliothek anstelle von Photon geschrieben - dort gibt es keine Speicherzuordnungen.
Es gibt noch Teile, die Sie nicht mit Ihren Händen schreiben, sondern Code generieren können. Wenn wir beispielsweise den Zustand der Welt an einen Kunden senden, schneiden wir die Daten aus, die er nicht benötigt. Solange wir dies mit unseren Händen tun und wenn eine neue Funktion erscheint und wir vergessen, diese Daten auszuschneiden, geht etwas schief. Tatsächlich kann dies durch Markieren eines Attributs erzeugt werden.
Fragen aus dem Publikum
- Was verwenden Sie zur Codegenerierung? Deine eigene Entscheidung?- Alles ist einfach - Hände. Wir dachten, etwas fertig zu machen, aber es stellte sich heraus, dass es schneller war, nur mit unseren eigenen Händen zu schreiben. Folgen Sie diesem Weg, es hat damals und heute gut funktioniert.
- Sie haben den Serverentwickler abgelehnt, aber nicht nur die Entwicklungszeit verkürzt, da derselbe Code wiederverwendet wird. Unity unterstützt nicht die neueste Version von C #, sondern verfügt über einen eigenen Motor unter der Haube. Sie können .NET Core nicht verwenden, Sie können nicht die neuesten Funktionen, bestimmte Strukturen und mehr verwenden. Leidet die Leistung nicht etwa ein Drittel darunter?- Als wir anfingen, all dies zu tun, dachten wir, dass es viel schneller hätte funktionieren sollen, um nicht Klassen, sondern Strukturen zu verwenden. Wir haben einen Prototyp geschrieben, wie es im Code aussehen wird, wie Programmierer diese Strukturen verwenden, um Logik zu schreiben. Und es war schrecklich unangenehm. Wir haben uns für den Unterricht entschieden und die Leistung, die wir jetzt haben, ist genug für uns.
- Wie lebst du jetzt ohne Interpolation? Und wie geben Sie vor, ein Spieler zu sein, wenn der Schnappschuss nicht im richtigen Rahmen erscheint?- Wir haben Interpolation, nur ist es nicht visuell, sondern auf den Paketen, die ĂĽber das Netzwerk kommen. Nehmen wir an, wir haben den 18., 19. und 20. Staat.
Der 18. kam, der 20. kam und der 19. ging entweder verloren oder hat ihn noch nicht erreicht - hier interpolieren wir ihn. Verwenden Sie einfach die Codegenerierung, um den Interpolationscode nicht zu schreiben.- Gibt es weitere Life-Hacks, um die Quaternionen stärker zu komprimieren?- Ich habe über 2D gesprochen - es gibt nur einen Alpha-Winkel, und bei neuen Projekten haben Quaternionen auch dort ihre eigenen Probleme. Bei Life-Hacks kann ich auch Folgendes sagen: Da wir UDP verwenden, damit die Eingabe nicht verloren geht, senden wir sie in Stapeln: von null bis zur fünften Eingabe, dann von der ersten bis zur sechsten und so weiter. Es ist billiger und der Versand ist besser."Aber die Reihenfolge der Wiedergabe von Eingaben auf dem Server spielt eine Rolle?"- Ja natürlich. - ( , , ), 2 : , .
— . ? ? 1000 , ? , ?— , . , -, , . , 30 .
— , ?— . , ( ), . — , , . - , , . , , , , . .
— ECS, , ? ?— 30 , . 80 , . .
— prediction. 20- - , , - — , ? , . - ?— : . (, 15-) 16-,17-,18- .
— ?— , . , , . Entity ( ), . — , . ID , .
— - — , , , ? , ?— , , . 3D , — , , - . , , . top-down, — . . , , , . .
— ?— . .
— , , - . - . - , , , 500 , , - - . ?— .

, .. 20- 20- , . — , . : 20- , ? , . , — - . , . , « - , 21-, 18-». : «, - ». .
— .. , ?— , .
— reliable UDP — - ?— Photon, Photon reliable UDP, unreliable, c .
— ?— , -. , . , . , . , . 100%, , 80%, .
— ?— , , Photon , MTU.
— ? ?— , , , . . , . , , , .
— , , ?— , . , . , , . , - . , . , .
— / — - . , .— , . , ( ), -, , -. , . — , .
— , - . ?— , . : ECS, . , ECS . , ECS . , . , , , ( , , , , , ). 2D , , 3D — . 3D , , . . - , . , - -, .
— , ECS , . , , C#?— — .
— .. ES ? , ECS — , , , . Das heißt, ECS — , .— , , . , . — , , . , O - , , .
— , ECS- ?— -, ECS , , ( ) — , . , — . — , , . , , , ..
Pixonic DevGAMM Talks