Beiträge von Akino Kiritani

    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 :)

    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 ;)

    Wäre nur interessant ob es auch über mehrer stunden so gut läuft und bei hoher Serverauslastung.


    Was hat denn jetzt der Server damit zu tun?
    Meinst du wegen dem Timer?


    So schlimm wäre das nun nicht.
    Interessant ist eher, wenn viele auf den Server connecten, auf dem die Datei liegt, u.a. wegen dem Traffic.
    Dann kommt noch die Internet Verbindung dazu, viele haben scheinbar noch eine Holzleitung...

    Du bist echt ein Held.


    Versuchst die ModelIDs von Fahrzeugen zu bekommen ohne das sie exestieren.


    Setz das bei OnVehicleSpawn oder OnPlayerStateChange rein.


    bei OnPlayerStateChange musst du dann halt noch eine Variable setzen, die dir sagt, ob der Tank schon gefüllt wurde

    Oder du erstellt das Lied als mp3 auf deinem oder irgendeinem vServer der das immer wiederholt


    Wie willst du denn das anstellen?
    Du müsstest dann theoretisch, einen Webcast erstellen bzw ein Webradio.


    Dann hast du aber das Problem, das der Spieler mittendrin einschaltet.
    Das ist daher auch keine Lösung^^

    Gibt es nicht.
    Timer ist auch ein blöde Idee und zwar deshalb,
    weil man theoretisch gesehen noch den Ping mit einberechnen muss,
    sprich die Zeit die der Client braucht um die Datei überhaupt abspielen zu können.
    Bei einem Stream bzw einer Musikdatei, die auf einem Server liegt, dauert es natürlich länger,
    als wenn die Datei auf dem Desktop liegt.


    Also ist es theoretisch gesehen, bisher nicht möglich ;)

    Ich weiß gar nicht was ihr euch so aufreget.
    Es ist eine Sache von 10 Sekunden einmal Strg+H zu drücken und bcmd mit ocmd zu ersetzen.


    Komisch das es dann voll funktionsfähig ist.
    Sachen gubts :huh: