Befreien Sie sich von den üblichen MUD-Zyklen

7

Ich arbeite an einer MUD-Engine und möchte es ein wenig anders machen als alle MUD-Spiele, die ich gespielt habe. Ich finde ein "Fahrrad" -System sehr langweilig. Eine der Ideen, die ich hatte, war, dass jeder Client-Socket in seinem eigenen Thread funktioniert. Ich bin mir bewusst, dass es nicht mit Hunderten von Spielern enden wird, aber ich würde gerne wissen, ob es Probleme gibt, "eine Menge" Threads in einem einzigen Prozess zu erstellen.

Oder welche andere Strategie könnte ich verwenden, wenn ich es (z. B. Kämpfe) in "Echtzeit" machen möchte.

Ich hoffe ihr versteht die Frage.

Vielen Dank.

Cybrix
quelle

Antworten:

14

MUD-Zyklen sind im Allgemeinen nicht vorhanden, da der Server Probleme hat, alles innerhalb der verfügbaren Zeit zu verarbeiten oder Netzwerkanforderungen schnell genug zu bearbeiten. Sie sind da, weil Spamming-Befehle so schnell wie möglich keine gültige Taktik sein sollten.

Lass einfach einen Abkling- / Aufladetimer für jede Fähigkeit haben. Abhängig von Ihrem sozialen Design kann dies auch "Bewegen" und "Sprechen" umfassen oder nicht.

Im Allgemeinen ist es sinnlos, mehr als einen Thread pro Kern für die Netzwerkverarbeitung in einem Spiel zu haben. Wenn Sie an die Paketverarbeitung gebunden sind, wird Ihr System durch einen Thread pro Kern maximal ausgelastet - mehr Threads würden den anderen nur die benötigte CPU-Zeit entziehen. Wenn Sie nicht an die Paketverarbeitung gebunden sind, ist ein Thread pro Kern klein genug, um den Rest des Systems nicht über zu viele Kontextwechsel zu beeinflussen.


quelle
Genau das, was diese Person gesagt hat :)
Speeder
3
Verdammt noch mal ... Wie auch immer, ich habe einmal ein MUD ohne Zyklus gesehen, und es war scheiße, weil einige Spieler einige seltsame Makros auf ihrem Client erstellt haben, und wenn du mit ihnen ins PvP gegangen bist, haben sie dich leicht verprügelt Kommandoflut, selbst wenn sie schwächer waren, schlugen sie dich manchmal mehrmals, bevor du überhaupt die Gelegenheit hattest zu lesen, was los war.
Speeder
Hmm, ich sehe den Punkt dort, aber das Hinzufügen verschiedener Befehle zu einer inneren Verzögerung (Kampfbefehl 3s, Bewegung sagen wir 2s und soziale 1s) Ich glaube, das würde dieses Problem beheben. Die anderen Schlachtexte werden ständig angezeigt. Einige Spieler treffen je nach Statistik mehr / schneller. Das ist mein Gedanke an das, was ich gerne machen würde
Cybrix
das war die Idee hinter der ganzen Sache. Ich kann es einfach nicht herausfinden, ob alles im selben Thread läuft. Für mich sieht es nach einer großen Schleife aus, um zu sehen, ob ein Spieler einen Befehl gepuffert hat, und ihn dann auszuführen. Aber was ist mit den regulären Angriffsbefehlen (ähnlich wie "weißer Schaden" in WoW)?
Cybrix
Führen Sie Ihr Spiellogik-Update mit einigen festen FPS aus, z. B. 30. Alle 2 Sekunden tritt alle 60 Frames ein Schaden auf. Es ist nur eine normale Spielschleife, aber ohne den Aufruf von render ().
5

Tut mir leid wegen der Thread-Nekromantie, aber dieses Problem ist mein LIEBLINGS-Haustierprojekt zum Lernen und Lehren von Parallelitätsmodellen und Frameworks!

Das Ausführen jedes Clients / Mobs in einem eigenen Thread ergibt eine natürliche Unterteilung, aber wie mehrere angemerkt haben, sind Threads teuer, wenn Sie mehr davon verwenden als Sie CPU-Kerne haben. Wenn dies kein zwingender Grund ist, es nicht in Ihrem MUD zu verwenden, ist es dennoch ein guter Grund, einen besseren Weg zu lernen.

Das Ausführen aller Clients in einer einzigen Spielschleife mit fester Zeit und Aktionen, die einige Schleifen umfassen, ist eine bekannte Methode aus der Welt der grafischen Spiele. Es bindet alles auf der Welt an denselben Zeitzyklus, obwohl eine ausreichende Feinkörnung der Schleifen dies maskieren kann. Der Hauptnachteil dieser Methode ist meines Erachtens, dass sie nicht von Natur aus parallelisierbar ist. Jemand bemerkte, dass Sie Threads erstellen können, um das Erstellen / Parsen / Transceiving von E / A, das Ausführen von KI usw. auf andere Threads zu verlagern. Die Parallelisierung der Hauptspiellogik erfordert jedoch eine grundlegende Änderung und viel Arbeit, um die Thread-Sicherheit zu gewährleisten.

Wenn Sie all diese Arbeiten erledigt hätten, hätten Sie wahrscheinlich etwas Ähnliches wie meinen aktuellen Favoriten, das Actor-Modell ( http://en.wikipedia.org/wiki/Actor_model ). Das Actor-Modell ist eine Time-Sharing-Strategie, die ziemlich genau dem entspricht, was Sie mit der One-Thread-per-Client-Idee vorgeschlagen haben. Wenn Sie es verwenden, codieren Sie Ihre "Akteure" wie eigenständige Threads, mit einigen Einschränkungen: Sie müssen ereignisgesteuert sein und können nur durch Weiterleiten von Nachrichten mit dem Rest des Systems kommunizieren (was anders, aber einfach ist). Das ereignisgesteuerte Bit bietet Platz für Ihr wirklich unabhängiges Timing, indem aktorspezifische Ereignisse so geplant werden, dass sie zu bestimmten Zeiten ausgelöst werden, z. B. wenn eine Aktion abgeschlossen ist oder mit einer bestimmten Client-Häufigkeit.

Unter der Haube verwendet die Implementierung eine Warteschlange (oder Warteschlangen) von Nachrichten, die von allen Akteuren generiert werden, und einen Pool von Threads, die Ihrer Anzahl von CPU-Kernen entsprechen. Die Threads ziehen Nachrichten aus den Warteschlangen und rufen die Nachrichtenbehandlungsmethoden des Empfängerakteurs auf, um sie zu verarbeiten. Sie werden im Kontext dieses Akteurs ausgeführt, bis die Nachricht "verarbeitet" wird. Aus Ihrer Sicht erhält jeder Akteur seinen eigenen Thread, wann immer er tatsächlich ausgeführt wird. Aus Sicht des Systems gibt es jedoch nur so viele Threads wie CPUs, um sie auszuführen.

Es gibt einige großartige Actor-Frameworks, nämlich Erlang / OTP und Akka, aber die Grundidee ist so einfach, dass Sie sie in jeder Sprache ohne den zusätzlichen Aufwand eines Frameworks implementieren können.

Der Vollständigkeit halber ist das Actor-Modell eigentlich nur die Kombination aus Nachrichtenübermittlung für die Thread-Sicherheit, ereignisgesteuerter Programmierung für die Parallelität und einem Thread-Dispatching-Mechanismus. Wenn Sie die Thread-Dispatch-Bits entfernen würden, hätten Sie ein "reaktives" System, das derzeit für die Skalierbarkeit im Allgemeinen sehr beliebt ist (siehe http://www.reactivemanifesto.org/ ). Sie können die Ausführung dann mehreren Computern in einer Cloud oder was auch immer zuordnen ... Sie haben die Idee ... was alles bedeutet, dass Ihr MUD-Programmierprojekt Ihnen möglicherweise marktfähige Programmierkenntnisse vermittelt. Hurra!

SAyotte
quelle
2

Sie können Kampfbefehle beim Eingang zulassen und dann nach Befehlen eine Zeitverzögerung hinzufügen, die davon abhängt, wie lange die Ausführung dauern würde.

Dragonrealms verwendet diese Methode für den Kampf sowie für viele andere Aktionen. Dort wird sie Roundtime genannt. Schwerere Waffen haben eine längere Zeit und Sie können sie reduzieren, aber nicht mit Stärke und Beweglichkeit eliminieren.

lathomas64
quelle
Das ist genau meine Idee dahinter. Aber ich dachte, ich würde es mit Multithread-Clients fahren. Aber jetzt höre ich, dass es kein guter Vorschlag ist: P
Cybrix
Warum sollten Sie Threads verwenden, die über das hinausgehen, was Sie für Sockets / Kommunikation verwenden dürfen?
Lathomas64
0

Die Vernetzung ist ohnehin serieller Natur (zumindest bis Sie in Glasfaserleitungen mit mehreren Tbit / s einsteigen). Es ist sinnvoll, einen Thread für Netzwerk-E / A getrennt von der Spielelogik und möglicherweise einige autonome Agent-Threads zu haben. Alles andere ist übertrieben.

Martin Sojka
quelle
Wenn Sie Multicore-Computer haben, würde ich mehr als einen Netzwerk-Thread empfehlen (bis zu einen pro Kern). Während jeder Socket netzwerkbeschränkt ist, ist das Lesen der Client-Anforderungen und das Erstellen der Spielstatus- / RPC-Antwortpakete zum Zurückschieben in die Sockets nahezu perfekt parallelisierbar.