MMO (oder zumindest erst mal MO) - Hilfe bei Ansatz?

Anfängerfragen zum Programmieren mit PureBasic.
Benutzeravatar
KatSeiko
Beiträge: 367
Registriert: 19.07.2008 07:47

MMO (oder zumindest erst mal MO) - Hilfe bei Ansatz?

Beitrag von KatSeiko »

Ich habe vor, eine Art Multiplayer-Spiel mit Server zu programmieren, erst mal für mein Heim-Netzwerk. Ich habe mir eine Datenbank über MS SQL Server 2008 Express zugelegt, habe mir mein Spielkonzept skizziert, und bin nun dabei, eine Server-Anwendung zu schreiben. :D
Ich weiß, es ist keine leichte Aufgabe - aber sie ist hoffentlich machbar.

Jetzt hab ich mein erstes Problem: Wie löse ich am besten die Sache mit den Ereignissen? :(
Wenn ein Spieler einen anderen angreift, soll von seinem Rechner die Meldung an den Server geschickt werden mit der Meldung "Spieler aktiviert Waffe(ID) auf Ziel(ID)". Dieser soll nun prüfen ob Energie und Munition vorhanden ist und alle X Sekunden berechnen, wie viel Schaden er auf Ziel(ID) anrichtet, bis das Ziel entweder zerstört wurde, Munition oder Energie ausgeht, oder die Waffe wieder deaktiviert wurde. Delay(y) erscheint mir an der Stelle die denkbar schlechteste Alternative zu sein...

Vielleicht hat jemand von euch Erfahrung damit und kann mir da weiterhelfen?
Win7 Ultimate x64, PureBasic 5.11

There is no substitute..
BildBildBild
Benutzeravatar
Bisonte
Beiträge: 2468
Registriert: 01.04.2007 20:18

Beitrag von Bisonte »

Client A -> Server : Achtung Angriff auf Client B

(Client A testet selbst ob Munition oder Energie vorhanden ist)

Server -> Client A: Ok. Dauert (Waffenschusszeit (evt.die Animationsdauer der schiessenden Spielerfigur )

Server rechnet aus, ob Treffer und wenn ja wieviel Schaden, Munitionsverbrauch etc.

Server -> Client B : Achtung du wirst angegriffen von Client A.

Client B -> Server : Ok. Dann sag mir was passiert ist.... (vielleicht eine AnimationsID oder sowas die dann abgespielt wird)

Server -> Client A : Ergebnis Kampf
Server -> Client B : Ergebnis Kampf

Server trägt neue Daten in die DB ein

So denk ich mir das grad...

Ich denke mal du hast in der DB einen Table "Spieler".
Dort solltest du momentane Ausrüstung und Munition/Energie speichern.
Ist auch ein (wenn auch relativ einfacher) Schutz vor Datenmanipulation...

Also Delays sind bei Netzwerksachen schöne Bremsen ;)
Du müsstest den Clients sagen, wie lange etwas dauert... diese machen dann z.B. schussanimation oder sowas und "belästigen in der Zeit nicht den Server...

Also der Server ist in meinen Augen "nur" der Datenjongleur...
die Clients die Bedienoberfläche ...

Edit: Hoffentlich schreib ich hier nicht zu "wirr"... oh man ich glaub ich muss ins Bett ;) dusselige Nachtschichten
PureBasic 6.21 (Windows x86/x64) | Windows11 Pro x64 | AsRock B850 Steel Legend Wifi | R7 9800x3D | 64GB RAM | GeForce RTX 5080 | ThermaltakeView 270 TG ARGB | build by vannicom​​
Benutzeravatar
gnasen
Beiträge: 578
Registriert: 01.08.2007 14:28
Computerausstattung: PB 4.60

Beitrag von gnasen »

Ich schreibe zur Zeit etwas ähnliches und kann Bisonte nur zustimmen.

Das wichtigste ist, Server und Client von Anfang an zu unterscheiden. Der Client darf auf keinem Fall Zugriff auf Spielrelevante Daten oder die DB bekommen.

Ich habe es so gelöst, dass es einen Pool gibt, in dem alle Spieler beim connecten landen. Bei jedweder interaktion werden aus dem Pool entsprechende User gezogen.
Besonderheit ist bei mir, dass man nur manchmal mit anderen agiert.

a) im Chat
b) im Spiel selbst

Dafür habe ich extra Listen angelegt, in denen alle Informationen dieser Instanz getrennt von allen anderen ausgewertet werden. Ansonsten würde der Rechenaufwand sehr groß. Eingebettete Listen sind hier, meiner Meinung nach, ein muss.

Bei mir sieht das so aus:

Client A -> Server: ID: 03131 Typus: 1232 Data: 3235
würde heissen: Client Blablub (infos sind ja auf dem Server, bzw DB) schickt eine Nachricht mit dem Typus (ich greife an) und den Datenblock (Spieler B)
Der Server schaut: Sind Spieler A und B in der selben Instanz? Ja. Ist Spieler A in der Lage anzugreifen? Ja. Trifft er? Nein.

Antwort:
Server -> Client A: ID: 03131 Typus: 3512 Data: 8314
und würde von den Clients entsprechend ausgewertet werden.

Die Clients dienen einzig und allein dem Input und der Grafischen Darstellung.

Der Aufwand ist enorm, wenn zB ein Eingangsevent drei Folgeevents auslöst. Davon braucht jetzt eines evtl Input von einem Client. Da der Server NICHT mit delay(1) abhängen kann, muss alles, was gerade in der Instanz los ist so gespeichert werden, dass beim nächsten Input quasi alles wie zum Ende des Vordurchlaufs ist.
pb 4.51
Benutzeravatar
Thorium
Beiträge: 1722
Registriert: 12.06.2005 11:15
Wohnort: Germany
Kontaktdaten:

Beitrag von Thorium »

Delay kannst du da auf keinen Fall verwenden. Du solltest nur ein einziges Delay in der Gameloop des Servers haben und das auch nur um die CPU-Last unter 100% zu bringen.

Wie schon geschrieben wurde, verwende Listen und Timer. Also, wenn du Schaden auf Zeit machen willst. Z.b. alle X Sekunden soll Schaden abgezogen werden. (Macht z.b. bei nem Flammenwerfer Sinn.) Dann leg ne Liste an, die alle laufenden Zeitangriffe beinhaltet. Mach dir dafür ne schöne Struktur, welche die Spieler-ID's des Angreifers und Opfers enthält, Waffen-ID, etc. und halt auch die Zeit, die der Angriff dauern soll. Die kannst du auch dynamisch mit Events vom Client aus noch erhöhen oder runtersetzen. Nun ackerst du in der Gameloop die Liste durch, senkst die Zeit-Dauer der Angriffe um die Zeit, die seid dem letzten durchackern der Liste vergangen ist (ElapsedMilliseconds). Prüfst ob eine volle Sekunde runter ist, seid der letzten Schadensberechnung. (Bei Schaden pro Sekunde) Dann berechnest du den Schaden und schickst den an die Clients. Ist die Zeit-Dauer auf 0 oder niedriger entfernst du den Zeit-Angriff aus der Liste.

Noch ein paar Tipps zum optimieren:

Datenbanken sind langsam! Nutze sie nur wenn nötig. Ansonsten entwickelt sich da unter Umständen ein Flaschenhals. Z.B. kannst du beim initialisieren einer Instanz schon alle für die Instanz relevanten Daten aus der Datenbank auslesen und hast somit direkten Zugriff darauf wärend die Instanz läuft.

TCP-Packete haben großen Overhead!
Ich weis jetzt nicht aus dem Kopf wieviele Bytes so ein Packet an Overhead hat aber es ist typischerweise um einiges mehr als die Datengröße eines Events. Das bedeutet, wenn du pro Packet nur 1 Event schickst, produzierst du einen gigantischen Overhead und da das Netzwerk/Internet der Flaschenhals bei einem MO ist, solltest du hier versuchen zu optimieren. Das heisst: Pack möglichst viele Events in ein Packet. In meinem aktuellen Spiel bastel ich auch grad an der Netzwerkfunktionalität und habe es dort so gelöst das ich einen Stack habe (Linked List) auf den ich die Events lege und alle X ms wird aus dem Stack ein Packet gebaut und auf die Reise geschickt. Desdo actionlastiger und schneller das Spiel ist, desdo geringer musst du die Zeit zum sammeln von Events festlegen. Da durch diese Technik natürlich eine Verzögerung entsteht. (Der Ping steigt.) Aber es veringert den Netztraffic signifikant.

Verstecke Verzögerungen.
Bei einem MMO kommt es immer zu Verzögerungen bedingt duch das Internet. Du kannst die Verzögerungen aber teilweise verstecken. Z.B.: Wenn der Client ein Angriffs-Event abschickt kann er schon die Animation des Angriffs starten und sollte nicht erst auf Antwort vom Server warten. So sollte es kein Problem sein das die Antwort des Servers vor Ende der Animation eintrifft und du dann noch eine Treffer oder Misslungen Animation dranhängen kannst + Schadenanzeige.
Du kannst auch Bewegungen interpolieren. Das heisst es gibt ein Event für ein Positionsupdate eines Spielers. Nun setzt du den Spieler bei den anderen Clients nicht einfach auf die neue Position, sondern lässt ihn mit Animation dorthin laufen. Dadurch entsteht zwar eine gewisse Asyncronität aber das ist nicht weiter tragisch, wenn diese gering bleibt. Bei zu großen Abweichungen, solltest du syncronisieren. Also dann einfach ohne Animation auf die neue Position setzen.
Zu mir kommen behinderte Delphine um mit mir zu schwimmen.

Wir fordern mehr Aufmerksamkeit für umfallende Reissäcke! Bild
Benutzeravatar
KatSeiko
Beiträge: 367
Registriert: 19.07.2008 07:47

Beitrag von KatSeiko »

Danke für eure Anregungen. Mal sehen, wie sich das entwickelt.

Also ich hab hier ne Datenbank, die aus einem Spiel namens EVE Online stammt. Unter http://www.eveonline.com/community/toolkit.asp ist der letzte Datenexport zu finden. Der Umfang des Backups (über 500 MB) zeigt schon recht imposant, wie sehr so eine Datenbank allein durch Verknüpfungen anschwellen kann.

Weiß eigentlich jemand von euch, wie man unter Vista (vielleicht mit Systemeigenen Tools) eine RAMDisk erstellt?
Win7 Ultimate x64, PureBasic 5.11

There is no substitute..
BildBildBild
Benutzeravatar
Thorium
Beiträge: 1722
Registriert: 12.06.2005 11:15
Wohnort: Germany
Kontaktdaten:

Beitrag von Thorium »

KatSeiko hat geschrieben:Der Umfang des Backups (über 500 MB) zeigt schon recht imposant, wie sehr so eine Datenbank allein durch Verknüpfungen anschwellen kann.
Ja, kann schon sehr groß werden. Wobei 500MB noch locker zu handeln sind. Die könnte man sogar komplett aus der Datenbank auslesen und im Speicher halten. Dann hat man die Datenbank quasie nur als Backup/Export. Gut, Suchfunktionen und sonstiges müsste man selbst schreiben. Ist aber auch nicht, der Akt.

500MB an Spieldaten im Speicher ist ja für nen Server kein Problem. Du musst bedenken das der vollkommen ohne Grafik, Sounds, etc. auskommt.
Zu mir kommen behinderte Delphine um mit mir zu schwimmen.

Wir fordern mehr Aufmerksamkeit für umfallende Reissäcke! Bild
Antworten