Laden...

Lidgren sendet falsche Werte

Erstellt von Drake vor 4 Jahren Letzter Beitrag vor 4 Jahren 1.888 Views
D
Drake Themenstarter:in
10 Beiträge seit 2019
vor 4 Jahren
Lidgren sendet falsche Werte

Guten Abend,
ich benutze derzeit die Lidgren Framework für ein Spiel und habe ein großes Problem, denn ich sende Daten an den Client doch es kommen nur zum Teil die richtigen Daten an.

Beim Clienten in der Methode checkDataType() im 2. Case beim string name wird ein falscher Wert ausgegeben, obwohl der Server einen String sendet. Wenn an dieser Stelle einen ReadInt32() schreibt, wird ein Zahlenwert ausgegeben, wo soll dieser Wert herkommen, wenn der Server ihn nicht sendet. Habe soweit die Knackpunkte kommentiert.

Server:


public void whileSchleife()
        {
            while (true)
            {
                NetIncomingMessage inc = server.ReadMessage();
                if (inc != null)
                {
                    switch (inc.MessageType)
                    {
                        case NetIncomingMessageType.ConnectionApproval:
                            
                            string s = inc.ReadString();
                            inc.SenderConnection.Approve();
                            Thread.Sleep(2000);
                            Console.WriteLine(s + " hat den Server betreten.");
                            break;
                        case NetIncomingMessageType.Data:
                            checkDataType(inc);
                            break;
                    }
                }
            }
        }

        public void checkDataType(NetIncomingMessage inc)
        {
            ServerType type = (ServerType)inc.ReadByte();
            switch (type)
            {
                case ServerType.FirstMessage:
                    NetOutgoingMessage successMessage = server.CreateMessage();
                    successMessage.Write((byte)ServerType.State);
                    successMessage.Write(true);
                    server.SendMessage(successMessage, inc.SenderConnection, NetDeliveryMethod.ReliableOrdered);

                    Player player = new Player(inc.ReadString(), inc.SenderConnection);
                    players.Add(player);

                    sendGameData(inc);
                    break;

            }
        }

private void sendGameData(NetIncomingMessage incomming)
        {
            NetOutgoingMessage gameInformation = server.CreateMessage();
            gameInformation.Write((byte)ServerType.Game);
            gameInformation.Write(localPlayers.Count);
            gameInformation.Write("Username"); // Dieser wird gesendet aber nicht empfangen. <---

            server.SendMessage(gameInformation, incomming.SenderConnection, NetDeliveryMethod.ReliableOrdered); // 
        }


Client


        private void listenToServer()
        {
            while (true)
            {
                NetIncomingMessage inc = theClient.ReadMessage();

                if (inc != null)
                {
                    Console.WriteLine("test123"+ inc.MessageType);
                    switch (inc.MessageType)
                    {
                        case NetIncomingMessageType.ConnectionApproval:
                            Console.WriteLine("hallo1");
                            checkDataType(inc);
                            
                            break;
                        case NetIncomingMessageType.Data:
                            Console.WriteLine("hallo");
                            checkDataType(inc);
                            break;
                    }
                }
            }
        }

 public void checkDataType(NetIncomingMessage inc)
        {
            if (inc != null)
            {
                type = (ServerType)inc.ReadByte();
                Console.WriteLine("Der Typ:" + type);
                switch (type)
                {
                    case ServerType.State:
                        bool state = inc.ReadBoolean();
                        connectionState = true;

                        break;
                    case ServerType.Game:
                        int players = inc.ReadInt16();
                        Console.WriteLine("Anzahl: "+ players); // Die Anzahl die vom Server gesendet wird stimmt überein.

                        string name = inc.ReadString(); // wenn man hier ReadInt32() schreibt wird eine Zahl ausgegeben, doch diese wurde von mir nie gesendet, ich frage mich wo diese abstammt.
                        Console.WriteLine(name); // Hier wird einfach ein leere angezeigt, obwohl hier Username ausgegeben werden müsste <---

                        break;
                }
            }
        }

5.657 Beiträge seit 2006
vor 4 Jahren

localPlayers.Count ist sicherlich ein 32-Bit-Integer, nicht 16 Bit.

Ansonsten:

mach es dir nicht zu schwer. Es gibt bereits fertige Frameworks und Protokolle, die genau das bieten.
In der Regel ist es weder ratsam noch notwendig ein eigenes Protokoll zu entwickeln (Selbstschulung und Verständnis ausgenommen).

Weeks of programming can save you hours of planning

D
Drake Themenstarter:in
10 Beiträge seit 2019
vor 4 Jahren

Dankeschön, es lag tatsächlich an diesem kleinen Fehler 👅

Das ich keine Framework für Protokolle benutze liegt daran, dass ich noch keine gefunden habe, die für mich passt. gRPC z.B macht nicht das, was ich umsetzen möchte.

5.657 Beiträge seit 2006
vor 4 Jahren

Was sind denn deine Anforderungen? Alles was du dazu in einem anderen Thread geschrieben hast, ist:

ich habe vor, ein kleines Spiel zu programmieren in C#, die Basis steht auch schon. Da die System.Net.Sockets Klasse für mich noch Neuland ist, habe ich eine Frage zur Koordination. Achso ich sollte eventuell erwähnen das die Verbindung schon steht und das ganze über TCP gehen muss, da keine Daten verloren gehen dürfen.

Das ist natürlich nicht viel Information. Im Code zeigst du, wie du einen Spielestatus senden und empfangen willst. Das ließe sich auch mit einer einfachen REST API umsetzen. Wenn du unbedingt Sockets benötigst, dann gibt es dafür auch fertige Bibliotheken. Als Faustregel würde ich sagen: Wenn du Daten unstrukturiert in einen Stream schreiben mußt, um sie per Netzwerk zu übertragen, dann setzt du mindestes eine Schicht zu weit unten an. Du siehst ja selbst, wie schnell man dabei einen Fehler macht, und wie schwierig es ist, das zu debuggen.

Das geht also sicherlich einfacher. Aber dann müßtest du mal erklären, was genau du vorhast, und was du bisher probiert hast. Siehe dazu auch unsere Tips in [Hinweis] Wie poste ich richtig?

Weeks of programming can save you hours of planning

16.806 Beiträge seit 2008
vor 4 Jahren

Das ich keine Framework für Protokolle benutze liegt daran, dass ich noch keine gefunden habe, die für mich passt. gRPC z.B macht nicht das, was ich umsetzen möchte.

Solche Aussagen finde ich immer persönlich spannend.
Wirkliches Interesse: wie hast Du denn evaluiert, dass Du bisher nichts gefunden hast?

Google setzt bei ihrer gesamten Kommunikation der internen Applikationen auf HTTP in Form von REST, GraphQL und gRPC.

Ich kann mir nur sehr sehr sehr sehr schwer vorstellen, dass Du einen Fall hast, bei dem nicht eine der drei Varianten passt.
gRPC ist so extrem mächtig, dass damit fast alles erschlagen werden kann.

D
Drake Themenstarter:in
10 Beiträge seit 2019
vor 4 Jahren

Guten Abend,
erstmal vielen Dank für die Antworten. Also kommen wir erstmal zu Rest, ich möchte gerne vermeiden etwas über HTTP zu machen. Zu gRPC, ich habe mir die Tutorial-Seite angeschaut (grpc.io) und bin dort nicht fündig geworden für meinen Einsatzbreich. Denn so wie ich das verstanden habe muss man in der Proto Datei immer die Methode mit einem rückgabe Wert des Servers angeben bzw. umgekehrt. Ich sende aber meist durch den Server nur einseiteige Nachrichten, d.h. der Client sendet eigentlich nur zum Start seinen Usernamen und jeden Zug einen Int für die Karte, die er gelegt hat und ansonsten empfängt der Client eigentlich nur vom Server. Zudem muss man immer die Dateitypen von vornherein in der Proto Datei niederschreiben, was mir nicht erlaubt Daten dynamisch zu versenden. Aber wie gesagt das Hauptproblem bleibt der vorgeschriebene rückgabe Wert, der bei mir nicht immer anfällt bzw. eigentlich nie. Das ich nichts gefunden habe liegt vermutlich daran, das ich dann anscheinend die falschen Begriffe eingegeben habe, denn ohne euch hätte ich z.B nicht mal gRPC gefunden. Ich habe dann irgendwann die Suche verändert indem ich "Multiplayer für Spiele C#" und wurde so auf die Lidgren Bibliothek aufmerksam. Da ich in der Multiplayer-Spieleentwicklung noch nie etwas gemacht habe, dachte ich dann, dass es so üblich ist, soweit unten im OSI Modell anzufangen. Es erschien mir auch einfacher, da ich mir alles so programmieren kann, das es genau meinen Wünschen entspricht, doch ist Lidgren nicht ganz bugfrei und wie ich merke, passieren auch schnell Fehler, die man nur schwer identifizieren kann.

T
2.219 Beiträge seit 2008
vor 4 Jahren

@Drake
Als Lösung für gRPC ohne return Wert gibt es wohl die Möglichkeit einen leeren Response anzulegen und diesen zu lierfern.
Ein direkt Keyword für void scheint es wohl nicht zu geben.

Ansonsten wäre es beim lesen deiner Antwort auch hilfreich mal Absätze zu verwenden.
Solche Blocktexte gehen beim lesen auf die Augen!

Anbei würde ich bei einem richtigen Multiplayer Spiel auch auf Http zwischen Client/Server verzichten und die Daten über eine UDP Verbindung dann direkt austauschen.
Fertige Lösungen wie Lidgren sind da schon ein hilfreicher Ansatz, sonst müsstest du direkt mit dem UdpClient arbeiten und die Daten dann direkt versenden.

T-Virus

Developer, Developer, Developer, Developer....

99 little bugs in the code, 99 little bugs. Take one down, patch it around, 117 little bugs in the code.

16.806 Beiträge seit 2008
vor 4 Jahren

Also kommen wir erstmal zu Rest, ich möchte gerne vermeiden etwas über HTTP zu machen.

Grund? HTTP ist das Protokoll.

Denn so wie ich das verstanden habe muss man in der Proto Datei immer die Methode mit einem rückgabe Wert des Servers angeben bzw. umgekehrt.

Dann hast es nicht verstanden. gRPC kennt den Empty-Typ, der wie null agiert (und als {} übertragen wird)..

Zudem muss man immer die Dateitypen von vornherein in der Proto Datei niederschreiben, was mir nicht erlaubt Daten dynamisch zu versenden.

"Dynamische Daten" in diesem Kontext kann es nicht geben.
Wenn Du vom Client "irgendwelche" Daten sendest, kann der Server sie auch nicht verarbeiten.

Egal wie Dein Szenario ist: mindestens die Grundstruktur muss bekannt sein.
Das gilt aber für alle Übertragungswege; egal ob REST, TCP, gRPC.

In gRPC gibt es dazu DynamicMessage bzw. Self-describing messages.

Für mich also das Fazit, dass Du gar nicht verstanden hast, was gRPC ist und leistet.
Wie gesagt: gRPC ist so erwachsen, flexibel und erprobt; ich bezweifle, dass Du einen Fall hast, der nicht abgedeckt ist.