Includes richtig erstellen | Hooking ganz einfach

Wichtiger Hinweis: Bitte ändert nicht manuell die Schriftfarbe auf schwarz sondern belasst es bei der Standardeinstellung. Somit tragt ihr dazu bei dass euer Text auch bei Verwendung unseren dunklen Forenstils noch lesbar ist!

Tipp: Ihr wollt längere Codeausschnitte oder Logfiles bereitstellen? Benutzt unseren eigenen PasteBin-Dienst Link
  • Hallo Community,


    aufgrund diverser Includes, die mich schon fast kotzen lassen,
    zeige ich euch mal, wie ihr jetzt richtig Includes schreibt.
    Dafür benötigen wir das sogenannte "hooking".


    Was ist Hooking?


    Hook ist englisch und bedeutet Haken (siehe z.B. Kapitän Hook).
    Im Endeffekt heißt es also nichts anderes als sich irgendwo einzuhaken bzw sich irgendwo dazwischen zu klemmen.


    Wozu wird Hooking benötigt?


    Hooking wird z.B. in Includes benötigt und zwar aus einem einfachen Grund.
    Includes sind theoretisch nichts weiter als Implementierung in die Scripte.


    Beispiel:


    Script:


    #include <BeispielInclude>


    forward Tutorial(playerid);
    forward SekundenTimer();


    main() { }


    public Tutorial(playerid)
    {
    return 1;
    }
    public SekundenTimer()
    {
    return 1;


    }




    Include:


    new Variable;
    new Float:FloatVariable;
    new Array[5];




    So würde der Code zusammengefasst aussehen
    new Variable;
    new Float:FloatVariable;
    new Array[5];


    forward Tutorial(playerid);
    forward SekundenTimer();


    main() { }


    public Tutorial(playerid)
    {
    return 1;
    }
    public SekundenTimer()
    {
    return 1;
    }



    Wie man nun sehr gut erkennen kann wurde #include <BeispielInclude>
    mit dem Inhalt der BeispielInclude ersetzt.


    Wozu ich euch das zeige?
    Einfach :D
    Wenn wir nun 2x eine Funktion im Script haben, spuckt der Compiler logischerweise einen Fehler aus,
    da er nicht genau weiß, was nun mit der 2. Funktion geschehen soll.



    Wie verhindert man dies?


    Theoretisch gar nicht.



    Oder doch?
    Prinzip ist einfach.
    Man hakt sich zwischen die Funktionen.
    Bitte bedenkt, das sich das zwar auf alle Funktionen ausweiten lässt,
    aber nicht immer Sinn macht.
    Ab wann was Sinn macht, lest ihr weiter unten.



    Hooking von Callbacks/Funktionen


    Dazu benutzen wir das ALS-Hooking verfahren.
    Das normale Hooking-Verfahren würde bei mehreren Hooks nur zu Problemen führen.
    Die ALS Methode ist bisher am verbreitesten.


    Es wird immer einen Include und Scriptteil und geben,
    das dient nur zu Übersicht ;)


    Wir nehmen mal als Beispiel das Callback OnPlayerConnect


    Script:


    #include <a_samp>


    #include <hooking>


    public OnPlayerConnect(playerid)
    {
    return true;
    }



    Hier ist das noch ziemlich Standardmäßig :D
    Aber nun zum eigentlichen.


    Wir wollen uns ja dazwischen klemmen, deshalb erstellen wir einen weitern
    Public, mit dem gleichen Namen.


    Aber, dann haben wir doch das gleiche Problem wie vorher...



    Ja, aber nur momentan, da kommt noch was dazu, also Geduld ;)



    Kommen wir zum eigentlichen.
    Wir müssen dem Compiler nun sagen, das es 2 verschiedene Funkionen/Callbacks sind.
    Das machen wir mit einem Macro/Define.


    #define OnPlayerConnect _OnPlayerConnect


    Vorsicht:
    Ihr dürft aber nicht den Fehler machen und es ganz nach oben setzen,
    sonst habt ihr eure Problem nicht umgangen.
    Es muss direkt unter den public, den ihr hooken wollt.


    Include:


    public OnPlayerConnect(playerid) // Die Parameter kommen natürlich immer auf die Funktion an ;)
    {
    return true;
    }


    #define OnPlayerConnect _OnPlayerConnect




    Aber moment.
    Nun bekommt ihr den Fehler, das _OnPlayerConnect noch nicht deklariert wurde,
    falls ihr versucht es zu compilen.


    Das liegt daran, das der Macro/Define erst dann anfängt zu wirken, wenn er erstellt wird.
    D.h. würde ich ihn nach oben setzen, würde er den neu erstellten public mit "umbennen".


    Um das nicht definiert Problem zu lösen erstellen wir einen forward mit dem Namen der hinter der Funktion steht, die gehookt werden soll.


    forward _OnPlayerConnect(playerid); // Die Parameter kommen natürlich immer auf die Funktion an ;)




    Aber HALT.


    Wenn wir 2 Includes haben die nach diesem Prinzip arbeiten, bekommen wir Fehler.
    Dafür ist das oben erwähnte ALS-Hooking erforderlich.
    Sofern die 2. Include dies auch verwendet.
    Wie gesagt es ist verbreitet, aber nicht jede Include benutzt dies auch ;)


    Dafür müssen wir Macro/Define etwas erweitern.


    Folgendes kommt dazu


    #if defined _OnPlayerConnect
    forward _OnPlayerConnect(playerid);
    #endif#
    if defined _ALS_OnPlayerConnect
    #undef OnPlayerConnect
    #else
    #define _ALS_OnPlayerConnect
    #endif
    //hier kommt der Macro hin (#define OnPlayerConnect _OnPlayerConnect)



    Kurze Erklärung.


    Als erstes wird geprüft, ob die Funktion die wir hooken wollen überhaupt verwendet wird,
    wenn ja wird, sie geforwardet um keine Fehler auszulösen.


    Danach wird geprüft, ob das ALS Hooking schoneinmal verwendet wurde,
    falls Ja, wird der Macro ab der Stelle ungültig gemacht.
    Falls Nein, wird ein Macro/Define gesetzt, zu Markierung für weitere Includes,
    damit keine Fehler auftreten.


    Direkt darunter, wird ein neuer(unser) Macro/Define erstellt.


    Fast Fertig.
    Bisher sollte es dann so aussehen.


    Include:
    public OnPlayerConnect(playerid) // Die Parameter kommen natürlich immer auf die Funktion an ;)
    {
    return 1;
    }
    #if defined _OnPlayerConnect
    forward _OnPlayerConnect(playerid); // Die Parameter kommen natürlich immer auf die Funktion an ;)
    #endif
    #if defined _ALS_OnPlayerConnect
    #undef OnPlayerConnect
    #else
    #define _ALS_OnPlayerConnect
    #endif
    #define OnPlayerConnect _OnPlayerConnect




    Momentmal, wenn ich es nun teste, wird OnPlayerConnect in meinem Gamemode bzw Script nicht aufgerufen.


    Ich sagte doch, wir sind erst fast fertig :P
    Wir haben uns nicht ganz dazwischen gehakt, sondern es eher abgefangen.
    Aber wir wollen dazwischen und nicht es abfangen.


    Das machen wir wie folgt.
    Wie wir es bereits weiter oben gemacht haben nutzen wir wieder die "#if defined" Überprüfung.
    Ist es vorhanden rufen wir das Callback auf, wenn nicht, geben wir einfach "true" zurück.
    Das verhindert, das wir unnötig Zeit verlieren und das der Aufruf nicht einfach ins Leere läuft.


    Am Ende sieht es dann für unser Beispiel wie folgt aus:
    public OnPlayerConnect(playerid)
    {
    #if defined _OnPlayerConnect
    return _OnPlayerConnect(playerid);
    #else return true;
    #endif
    }





    Es gibt aber noch die Möglichkeit des direkten Funktionsaufrufs.
    Da gibt es nicht viel zu beachten,
    einfach die Funktion mit dem neuen Namen aufrufen,
    hier wäre das:
    _OnPlayerConnect(playerid);




    CallLocalFunktion, funktioniert wie SetTimerEx.
    Das brauch ich wohl nicht zu erklären ^^


    Nun sind wir fertig ;)

    "Bevor ich mir Informationen aus der "Bild" hole,
    werde ich anfangen, Wahlergebnisse danach vorauszusagen,
    neben welchen Busch unsere Katze gepinkelt hat."

    Margarete Stokowski

    7 Mal editiert, zuletzt von Akino Kiritani () aus folgendem Grund: Tutorial an den neuen BBCode angepasst - doofer Leerzeichenpraser ._.

  • Das Prinzip ist das gleiche wie vorher, nämlich ALS_Hooking,
    nur benutzen wir hier keine Forwards bzw Publics sondern müssen hier direkt in das Native System eingreifen.
    Desweitern werden wir hier stocks benutzen,
    publics sind hier nutzlos, da wir sie nicht per CallLocalFunction oder Timer aufrufen.


    Ok, greifen wir ein.
    Zu erst müssen wir eine eigene Native erstellen und dem die Funktion zuweisen.
    Hier werde ich SendClientMessage als Beispiel nehmen ;)


    C
    native __SendClientMessage(playerid,color,const string[]);


    Nun haben wir zwar unsere eigene Native,
    aber wenn wir den Server nun starten würden, käme "File or Function not found".
    Der Grund ist der, die Native ist nirgends registriert.
    Sprich der Server kennt diese nicht.


    das umgehen wir, einfach, da wir hier ja kein Plugin schreiben, mit einer einfachen zuweisung.
    Auch hier gilt, das wir uns dazwischen hängen wollen.


    C
    native __SendClientMessage(playerid,color,const string[]) = SendClientMessage; // Wir weisen hier unsere Native zu, das sie wie SendClientMessage funktionern soll. Das ist Später wichtig.


    Nun erstellen wir unseren Stock.


    Achtung: Er darf nicht wie die Native lauten.


    C
    stock _SendClientMessage(playerid,color,const string[])
    {
    	return 1;
    }


    Das ist nun unsere "neue" SendClientMessage Funktion.
    Diese hooken wir genauso, wie die Callbacks, siehe oben.




    Aber moment, was machen wir nun, wenn wir die alte SendClientMessage verwenden wollen?
    Gute Frage - dafür haben wir ja unsere native.


    Die Include dürfte nun so aussehen:



    So könnt, ihr auch euren Funktionen neue Parameter zuweisen ;)


    Ich hoffe ihr habt verstanden was ihr gelesen habt,
    falls Fragen oder Ergänzungen sind, dafür bin ich immer offen :)

    "Bevor ich mir Informationen aus der "Bild" hole,
    werde ich anfangen, Wahlergebnisse danach vorauszusagen,
    neben welchen Busch unsere Katze gepinkelt hat."

    Margarete Stokowski

    3 Mal editiert, zuletzt von Akino Kiritani () aus folgendem Grund: BBCode Anpassung

  • #if defined _ALS_OnPlayerConnect
    #undef OnPlayerConnect
    #else
    #define _ALS_OnPlayerConnect
    #endif
    #define OnPlayerConnect _OnPlayerConnect


    Irgendwie peil ich das gerade nicht
    Ich hab das ja auch und OnPlayerConnect reagiert nicht
    Wie meinst du das mit den CallLocalFunktion?

    All in all it's just another brick in the wall

    • Du prüfst, ob der Prüf-Hook schon gesetzt wurde
    • Wenn ja -> entfernen des eigentlichen Hooks
    • Wenn nein -> setzen des Prüf-Hooks
    • Setzen des eigentlichen Hooks

    Wenn der Prüf-Hook ( _ALS_OnPlayerConnect ) gesetzt ist, ist auch der eigentliche Hook ( _OnPlayerConnect ) gesetzt ;)

  • Setzen des eigentlichen Hooks


    Da muss ich dich kurz verbessern.


    Setzen des neuen Hooks.


    Ich hab mir mal sein Problem angesehen,
    es liegt bzw lag am fehlenden Aufruf der gehookten Funktion

    "Bevor ich mir Informationen aus der "Bild" hole,
    werde ich anfangen, Wahlergebnisse danach vorauszusagen,
    neben welchen Busch unsere Katze gepinkelt hat."

    Margarete Stokowski

  • Ich verstehe den Sinn nicht ?(
    Naja ich verstehe das alles nicht :D

  • Sehr gut erklärt aber ich denke das ein Anfänger sowas kaum verstehen wird...

    [tabmenu][tab='Angebote','http://cdn3.iconfinder.com/data/icons/glyph/227/Tag-48.png']

    + Die Preise liegen bei 5-100+€ Ablauf:
    + Entweder ihr addet mich in Skype (PN vorher Schreiben) oder Ihr schreibt eine PN an mich (Betreff - Euer Wunsch z.B. Filterscript)
    + So nun schreibt ihr mir was ihr alles in dem Script haben wollt ich werd euch dann sagen ob ich es hinbekomme.
    + Dann machen wir ein groben Preis aus. Ich werde das Script erstellen und es zusammen mit dem Kunden Testen.



    [tab='Kontakt','http://cdn3.iconfinder.com/data/icons/line/36/person_add-48.png']
    edmix23

    + Bitte beim Adden angeben wer ihr seit oder per PN bescheid sagen!
    [tab='Zahlungs Methoden','https://cdn3.iconfinder.com/data/icons/line/36/check_money-32.png']
    +Paypal!
    +Direkte Banküberweisung

  • do.de - Domain-Offensive - Domains für alle und zu super Preisen
  • und meine wiki bewerbung ist immernoch nicht bearbeitet kam die vielleicht ausversehen in mülleimer oda so ?


    Nein, ich vergess das immer nur, da scheinbar die Leute der Meinung sind mir aus meinen 30 ungelesenen 35 - 38 zumachen,
    deshalb hab ich auch den Satz in der Signatur ;)


    @Rocky
    Das hat nur den Sinn das Includes endlich auch mal Includes sind und nicht zu Codeschnipseln werden.
    Beispiel -> B_Stream
    Erst war es ja nötig
    Beavis_OnPlayerConnect(playerid);
    mit einzubinden.


    Nachdem ich ihm das erklärt hab und dem Tutorial muss man das ja nicht mehr ;)


    @TheO
    Ich glaub auch nicht das ein Anfänger, auf die Idee kommt eine Komplexe Include zu schreiben ;)

    "Bevor ich mir Informationen aus der "Bild" hole,
    werde ich anfangen, Wahlergebnisse danach vorauszusagen,
    neben welchen Busch unsere Katze gepinkelt hat."

    Margarete Stokowski

  • Zitat

    das ergibt in der .amx compiliert folgendes


    Müsstest du ausbessern, denn wie die AMX Datei compiliert aussieht würde man kaum verstehen. Die Scriptsprache ist nur eine vereinfachung der eigentlichen Maschinensprache.
    Ich denke, dass

    Zitat

    so würde der Code zusammengefasst aussehen


    deine Erklärung besser bezeichnet.


    Ansonsten feines Tutorial, haste fein gemacht :love:


  • Ich glaub auch nicht das ein Anfänger, auf die Idee kommt eine Komplexe Include zu schreiben ;)



    Stimmt hast eigentlich recht ;D

    [tabmenu][tab='Angebote','http://cdn3.iconfinder.com/data/icons/glyph/227/Tag-48.png']

    + Die Preise liegen bei 5-100+€ Ablauf:
    + Entweder ihr addet mich in Skype (PN vorher Schreiben) oder Ihr schreibt eine PN an mich (Betreff - Euer Wunsch z.B. Filterscript)
    + So nun schreibt ihr mir was ihr alles in dem Script haben wollt ich werd euch dann sagen ob ich es hinbekomme.
    + Dann machen wir ein groben Preis aus. Ich werde das Script erstellen und es zusammen mit dem Kunden Testen.



    [tab='Kontakt','http://cdn3.iconfinder.com/data/icons/line/36/person_add-48.png']
    edmix23

    + Bitte beim Adden angeben wer ihr seit oder per PN bescheid sagen!
    [tab='Zahlungs Methoden','https://cdn3.iconfinder.com/data/icons/line/36/check_money-32.png']
    +Paypal!
    +Direkte Banküberweisung

  • 10/10 Ein Super Tutorial


    Mir hatte es auch damals geholfen, als mich BlackAce auf das Hooking von meiner Gangschaltungs-Include angesprochen hat.
    Es hier nochmal als Tutorial zu sehen, ist sehr gut, falls man mal etwas vergisst oder so ^^

  • 98% der User verstehen nicht mal was "Hooking" ist. Mal abgesehen, davon, dass das Tutorial total unübersichtlich ist und eine genaue Definition was "Hooking" eigentlich ist nicht vorhanden ist, ganz in ordnung. Wobei ich mich immer Frage, ob das alles für einen SA:MP Server so sinnvoll ist. Ich denke hier gehen die Meinungen sehr stark auseinander ;)

    Chief Technology Officer (CTO)


    Interesse an folgenden Domains?

    fivemp.de - planet-zoo.de

    Jetzt anschreiben :)

  • Ich gebe zu, das es etwas unübersicgtlich ist, das liegt aber an der Formatierung :D


    Was Hooking ist steht doch relativ weit oben ;)


    Hooking ist ungefähr vergleichbar mit einem Filterscript ;)
    Daher viele hooks mach schon was aus, da das eigentliche Callback viel später aufgerufen wird.

    "Bevor ich mir Informationen aus der "Bild" hole,
    werde ich anfangen, Wahlergebnisse danach vorauszusagen,
    neben welchen Busch unsere Katze gepinkelt hat."

    Margarete Stokowski

  • Naja, ich denk mal man kann es einfach mit der include-Funktion PHP vergleichen. Letzendlich implementiert man einfach etwas in das Skript ;)
    Mehr ist es letztendlich auch wiederrum nicht. Dennoch, sonst ist das Tutorial gut. Will ja auch nicht immer alles schlecht reden ;)

    Chief Technology Officer (CTO)


    Interesse an folgenden Domains?

    fivemp.de - planet-zoo.de

    Jetzt anschreiben :)