Angepinnt Debugnachrichten

    Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

    • Debugnachrichten

      Das hier ist kein Tutorial im Eigentlichen Sinne,sondern ein Tipp
      für alle die weiter kommen möchten mit ihren Scriptfähigkeiten indem sie Selbstständig
      ihre Fehler finden und beheben. Es soll euch helfen, eure Fehler im Code zu verstehen und zu beheben.

      Das Stichwort sind Debug-Notes oder einfach auch Debug-Nachrichten.
      Das sind Nachrichten bzw Texte, die ihr in euren Code einbaut, um nachzuvollziehen
      mit welchen Werten euer Script welchen Weg durchläuft ( Kein richtiger Weg, aber wir können
      uns die unzäglichen if / else if / else Bedinungen,Schleifen,Codeblöcke usw doch so vorstellen, oder ;]? )
      .
      Ich verwende sie persönlich sehr oft,denn es kommt immer mal wieder vor das einem Fehler unterlaufen.

      Debug-Notes werden verwendet, um den Grund zu finden, wieso etwas
      nicht so funktioniert, wie man es meistens möchte.

      Nehmen wir eine Ganz simple Abfrage, um zu prüfen ob iInput gleich iValue ist.
      Das Beispiel ist jetzt ziemlich banal, aber es soll nur die grobe Form darstellen wie
      es funktionieren soll.
      iInput könnte bspw eine globale Variable sein, die sich merkt, welcher Spieler zuletzt
      gejoint ist.

      PAWN-Quellcode

      1. new
      2. iInput = 14,
      3. iValue = 4;
      4. if(iInput == iValue) {
      5. // Code
      6. // Noch mehr Code
      7. // Code Ende
      8. }

      Nun gut. Sollte die Abfrage scheitern, hätten wir keine Informationen darüber, wieso es dazu kommt.
      Da wir in der Abfrage zwei Integer-Werte vergleichen,sollten wir uns diese
      doch am besten ausgeben lassen, falls die Abfrage false ergibt.

      PAWN-Quellcode

      1. new
      2. iInput = 14,
      3. iValue = 4;
      4. if(iInput == iValue) {
      5. // Code
      6. // Noch mehr Code
      7. // Code Ende
      8. }
      9. else {
      10. printf("DEBUG: iValue %d iInput %d",iValue,iInput);
      11. }
      Alles anzeigen

      Man kann auch direkt über die if() Abfrage die Debug-Notes einfügen.Ist Gewöhnungssache.

      PAWN-Quellcode

      1. new
      2. iInput = 14,
      3. iValue = 4;
      4. printf("DEBUG: iValue %d iInput %d",iValue,iInput);
      5. if(iInput == iValue) {
      6. // Code
      7. // Noch mehr Code
      8. // Code Ende
      9. }

      Das ist jetzt ein völlig frei erfundenes Beispiel, dass nur den Grundaufbau zeigt.Natürlich
      würde es in eurem Script viel weiter gehen und ihr solltet dann auch immer weitere Debug-Infos
      für euch hinzufügen,um dem Fehler auf die Spur zu kommen.

      PAWN-Quellcode

      1. public OnPlayerDeath(playerid,killerid,reason) {
      2. PlayerDeaths[playerid]++;
      3. PlayerKills[killerid]++;
      4. // Mehr Code
      5. printf("PlayerDeaths[%d] %d PlayerKills[%d] %d",playerid,PlayerDeaths[playerid],killerid,PlayerKills[killerid]);
      6. return 1;
      7. }

      Auch ein ziemlich simpler Code.Ich würde einfach mal tippen,dass Einigen nicht auffällt, dass
      dieser Code unter Umständen zu einem Stopp im Script kommt.
      Der Fehler kommt sehr häufig vor,ja, ich habe das manchmal auch übersehen.
      Angenommen man wird von einem Mitspieler getötet der die ID 15 hat.Man selber ist ID 4

      PAWN-Quellcode

      1. public OnPlayerDeath(playerid,killerid,reason) {
      2. PlayerDeaths[4]++;
      3. PlayerKills[15]++;
      4. // Mehr Code
      5. printf("PlayerDeaths[%d] %d PlayerKills[%d] %d",4,PlayerDeaths[4],15,PlayerKills[15]);
      6. return 1;
      7. }

      Alles Okay soweit.Der Code wird Fehlerfrei funktionieren.Was ist aber,wenn man Selbstmord begeht?
      ( Man muss ja immer alle Möglichkeiten durchtesten. )
      Dann ist die killerid INVALID_PLAYER_ID ( 0xFFFF ) oder auch 65535.Wir sind weiterhin ID 4.

      PAWN-Quellcode

      1. public OnPlayerDeath(playerid,killerid,reason) {
      2. PlayerDeaths[4]++;
      3. PlayerKills[65535]++; // index out of bounce! 65535 ist definitiv größer als MAX_PLAYERS
      4. // Wird nicht weiter ausgeführt - Mehr Code
      5. printf("PlayerDeaths[%d] %d PlayerKills[%d] %d",4,PlayerDeaths[4],15,PlayerKills[15]);
      6. return 1;
      7. }

      Jetzt würde man höchstwahrscheinlich erst gar nicht bis zum printf() im Code gelangen,da vorher
      mehr oder weniger der Code gestoppt wird. Jetzt bringt uns die Debug-Note leider nichts.
      Daher ist es oft noch hilfreich, einzelne Debug-Notes zu setzen um zu sehen, bis zu welcher Operation der Code Fehlerfrei läuft.
      Am besten ihr fügt auch eine Debug-Note ein,dass die Funktion überhaupt aufgerufen wurde.Dazu noch alle
      Parameter die übergeben werden.

      PAWN-Quellcode

      1. public OnPlayerDeath(playerid,killerid,reason) {
      2. printf("DEBUG: OnPlayerDeath( %d , %d , %d )",playerid,killerid,reason);
      3. PlayerDeaths[playerid]++;
      4. printf("DEBUG: 2");
      5. PlayerKills[killerid]++;
      6. printf("DEBUG: 3");
      7. // usw usf
      8. return 1;
      9. }

      Anhand der Debug-Notes solltet ihr auswerten können,wo der Fehler liegt. Natürlich muss
      man sich jetzt auch selber bischen anstrengen und den Fehler finden, doch so ist es definitiv
      leichter für jeden seine Fehler selber zu finden, ohne bei jeder Fehlermeldung nach Hilfe zu nachzufragen.

      In der Konsole ( serverlog ) wird ausgegeben bei Selbstmord:

      DEBUG: OnPlayerDeath( 4, 65535, 0 )
      DEBUG: 2

      Jetzt sollte wohl klar sein,dass es an folgender Zeile liegt:

      PAWN-Quellcode

      1. PlayerKills[killerid]++;


      Den letzten Schritt und den Fehler fixen müsst ihr aber selber machen. Ich
      geb den Code aber trotzdem mal richtig an:

      PAWN-Quellcode

      1. public OnPlayerDeath(playerid,killerid,reason) {
      2. printf("DEBUG: OnPlayerDeath( %d , %d , %d )",playerid,killerid,reason);
      3. PlayerDeaths[playerid]++;
      4. printf("DEBUG: 2");
      5. if( killerid != INVALID_PLAYER_ID ) {
      6. PlayerKills[killerid]++;
      7. printf("DEBUG: 3");
      8. }
      9. // usw usf
      10. return 1;
      11. }
      Alles anzeigen




      Nehmen wir ein weiteres Beispiel ( Aus dem Forum etwas gekürzt )

      PAWN-Quellcode

      1. // Folgende Variablen gibt es:
      2. //
      3. // new bool:Eingeloggt[MAX_PLAYERS];
      4. // new s[128];
      5. // weiteres:
      6. // #define DIALOG_REGISTER 5
      7. //
      8. // Es soll ein REGISTER Dialog erstellt werden.
      9. // Die Dialogid ist DIALOG_REGISTER ( 5 ) und es soll in dieses Fenster
      10. // ein Passwort eingegeben werden.
      11. // Der Code stand irgendwo hier im Forum ... ist nicht original von mir
      12. //
      13. public OnDialogResponse(playerid, dialogid, response, listitem, inputtext[])
      14. {
      15. if(dialogid == DIALOG_REGISTER)
      16. {
      17. if(!Eingeloggt[playerid])
      18. {
      19. if(response)
      20. {
      21. if(!strlen(inputtext))
      22. {
      23. GetPlayerName(playerid,Name,sizeof(Name));
      24. format(s,sizeof(s),"acc/%s.ini",Name);
      25. if(!dini_Exists(s))
      26. {
      27. dini_Create(s);
      28. dini_IntSet(s,"Passwort",udb_hash(inputtext));
      29. }
      30. }
      31. }
      32. }
      33. }
      34. return 1;
      35. }
      Alles anzeigen

      Dem Geschultem Auge wird relativ schnell auffallen wo der Fehler liegt.Nicht schlimm wenn man es
      nicht sieht.
      Wir kommen also nicht dahinter wo jetzt der Fehler liegt,was machen wir also?

      Wir könnten jetzt natürlich einen Thread im Forum erstellen mit einem Threadtitel,
      der nicht gerade Aussagekräftig ist und einer sehr geringen Information zum eigentlichem Problem. Nach
      spätestens 1Stunden pushen wir und fragen uns,wieso uns bisher keiner geholfen hat.

      Oder,wir fangen an den Code mit Debug-Notes zu füllen um nachvollziehen zu können,bis vohin
      der Code abläuft.
      Nun testen wir das ganze nochmal um auch die Debug-Notes zu erhalten mit den Daten die wir danach auswerten.

      PAWN-Quellcode

      1. public OnDialogResponse(playerid, dialogid, response, listitem, inputtext[])
      2. {
      3. printf("OnDialogResponse(%d , %d , %d , %d , '%s')",playerid, dialogid, response, listitem, inputtext);
      4. printf("DEBUG: 1 - %d == %d ( dialogid == DIALOG_REGISTER )",dialogid,DIALOG_REGISTER);
      5. if(dialogid == DIALOG_REGISTER)
      6. {
      7. printf("DEBUG: 2 - %d ( !Eingeloggt[playerid] )",!Eingeloggt[playerid]);
      8. if(!Eingeloggt[playerid])
      9. {
      10. printf("DEBUG: 3 - %d ( response )",response);
      11. if(response)
      12. {
      13. printf("DEBUG: 4 - %d '%s' ( !strlen(inputtext) inputtext)",!strlen(inputtext),inputtext);
      14. if(!strlen(inputtext))
      15. {
      16. printf("DEBUG: 5");
      17. GetPlayerName(playerid,Name,sizeof(Name));
      18. printf("DEBUG: 6 - '%s' ( Name )",Name);
      19. format(s,sizeof(s),"acc/%s.ini",Name);
      20. printf("DEBUG: 7 - '%s' ( s )",s);
      21. printf("DEBUG: 8 - %d ( !dini_Exists(s) )",!dini_Exists(s));
      22. if(!dini_Exists(s))
      23. {
      24. printf("DEBUG: 9");
      25. dini_Create(s);
      26. printf("DEBUG: 10");
      27. dini_IntSet(s,"Passwort",udb_hash(inputtext));
      28. printf("DEBUG: 11");
      29. // usw.
      30. }
      31. }
      32. }
      33. }
      34. }
      35. return 1;
      36. }
      Alles anzeigen

      Haben wir das getan,sehen wir uns die Debug-Notes in der Log an.
      server_log.txt
      OnDialogResponse(0 , 5 , 1 , 0 , 'meinpasswort')
      DEBUG: 1 - 5 == 5 ( dialogid == DIALOG_REGISTER )
      DEBUG: 2 - 1 ( Eingeloggt[playerid] )
      DEBUG: 3 - 1 ( response )
      DEBUG: 4 - 0 'meinpasswort' ( !strlen(inputtext) inputtext)


      Wir wissen nun also bis wohin der Code abläuft anhand der Debug-Notes.
      Anscheinend geht es hier nicht mehr weiter

      PAWN-Quellcode

      1. if(!strlen(inputtext))

      Nun,schauen wir uns mal den Code genauer an. strlen() gibt die Länge des Strings zurück.
      In der Abfrage wollen wir aber überprüfen,ob die Länge des Strings 0 ist (!).Die Sache ist aber,dass
      wir als Passwort "meinpasswort" eingegeben haben.Die Länge ist also definitiv nicht 0. Sondern
      12 im Beispiel von "meinpasswort"

      Wir haben also den Fehler gefunden.Es liegt daran,dass wir fälschlicherweise in der Abfrage überprüfen,ob der
      String leer ist bzw keiner eingegeben wurde, anstatt zu schauen ob er überhaupt existiert

      PAWN-Quellcode

      1. if(strlen(inputtext))



      Natürlich,wozu ist das Ganze gut. Es soll dabei helfen, selbstständig seine Fehler zu finden anstatt immer
      von Anderen Hilfe in Anspruch zu nehmen. Klar ist das Forum dazu da, um euch bei Fehlern zu helfen,doch
      wäre es nicht besser, man schafft es auch alleine seine Fehler zu finden ? Falls man es wirklich nicht
      schafft seinen Fehler zu finden nachdem man es probiert hat durch die Debug-Notes, kann man immernoch nachfragen.



      Ich selber benutzen auch oft diese Technik um meine Fehler zu finden. Irgendwo schleicht sich doch bei
      jedem von uns der ein oder Andere Fehler ein, den wir nicht auf den ersten Blick sofort erkennen.
      Passend dazu habe ich mir vor langer Zeit auch eine kleine Funktion geschrieben,damit Ich mir
      Ingame die letzten Debug-Notes ansehen kann.
      Download < debugviewer >


      Include einfügen und an den Stellen,wo ihr eine Debug Nachricht einfügen wollt folgendes:

      PAWN-Quellcode

      1. Debug_AddEntry("Das ist ein %s mit %d Worten und pi %.2f", "Test",8,3.1415); // - Mit auto-format
      2. Debug_AddEntry("Das ist ein ein simpler Test",0); // - Falls kein format-Parameter,einfach 0 eintragen

      An der gewünschten Stelle noch

      PAWN-Quellcode

      1. Debug_ShowPanel(playerid)

      ,wenn ihr dem Spieler das Panel anzeigen wollt.



      Falls es noch Fragen,Anmerkungen oder Sonstiges gibt könnt ihr die natürlich gerne stellen :p
    • RE: Debugnachrichten

      Goldkiller schrieb:

      Ich selber benutzen auch oft diese Technik um meine Fehler zu finden. Irgendwo schleicht sich doch bei
      jedem von uns der ein oder Andere Fehler ein, den wir nicht auf den ersten Blick sofort erkennen.
      Passend dazu habe ich mir vor langer Zeit auch eine kleine Funktion geschrieben,damit Ich mir
      Ingame die letzten Debug-Notes ansehen kann.
      Download < debugviewer >

      SendClientMessage ist InGame ebenfalls recht nuetzlich, wenn man es nicht in Massen verwendet und nach dem debuggen entfernt, oder sich inetwa soetwas baut:

      PAWN-Quellcode

      1. #define DEBUG
      2. #ifdef DEBUG
      3. #define SendClientMessage_DEBUG SendClientMessage
      4. #define SendClientMessageToAll_DEBUG SendClientMessageToAll
      5. #else
      6. #define SendClientMessage_DEBUG //
      7. #define SendClientMessageToAll_DEBUG // - oder wenn man nicht auf die debug Nachrichten verzichten moechte, aber nicht fuer jeden sichtbar: #define SendClientMessageToAll_DEBUG(x, y) printf("%s", y)
      8. #endif

      Damit braucht man nur noch die DEBUG definition auskommentieren, wenn man das Script auf einem public server verwenden moechte.

      PS.: Sollte jetzt keine Kritik an deinem debugviewer sein, sondern nur ein Vorschlag wie man das Tutorial ein wenig erweitern kann - finde den debugviewer ganz gut, denn er scheint aenhlich einfach zu implementieren zu sein, wie ein Aufruf zu printf. ;)
      "#pragma tabsize 0", "#pragma semicolon 0" und "#tryinclude" anstatt "#include" koennen viele Probleme mit fehlenden Dateien, nervigen Einrueckungen und dem nutzlosen Semikolon am Ende einer Zeile loesen. Aber Achtung: Bei dem schreiben von moeglichst vielen Befehlen in einer Zeile, was fuer einen echten, platzsparenden, Scripter unerlaesslich ist, muss man weiterhin ein semikolon nach den Befehlen setzen.
      Wenn diese Tipps nicht euer Problem geloest haben, dann schreibt einfach folgenden Code an den Anfang des Skripts:

      Quellcode

      1. main(){}
      2. #endinput
      Nun sollte Pawn euch keine Fehler mehr beim Kompilieren zeigen.
      Viel Spass beim platzsparenden Scripten.