Nützliche Codeschnipsel

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
  • Ich weiß gar nicht, ob es solch eine Funktion schon gibt, oder ob man die einfacher auslesen kann, aber hiermit kann man überprüfen, ob die jeweilige Waffen-ID überhaupt existiert.
    stock IsValidWeaponID(weaponid)
    {
    switch(weaponid)
    {
    case 0..18:return 1;
    case 22..46:return 1;
    default:return 0;
    }
    return 0;
    }
    Beispiel:
    if(!IsValidWeaponID(waffenid))return SendClientMessage(playerid,-1,"Waffen-ID existiert nicht!");
    Viel Spaß damit! :thumbup:

  • Ich hab hier auch mal wieder paar Sachen :D


    SWAP
    Als erstes die gute alte SWAP Funktion ohne Variablen (ich weiß ist schon alt, habe ich hier aber noch nicht gesehen):


    #define SWAP(%0,%1) (((%0)^=(%1)),((%1)^=(%0)),((%0)^=(%1)))


    new a=5,b=10;
    SWAP(a,b);
    printf("a: %d | b: %d",a,b); //->Output: a: 10 | b: 5


    TotalBits
    Als nächstes eine sehr nützliche Funktion, wenn man die Anzahl an 1nser Bits in einer Zahl bestimmen will:


    Beispiele:


    1. 0xF = 15 = 0b1111 //Wir sehen hier 4x die 1
    2. 0xA = 10 = 0b1010 //Hier sehen wir 2x die 1


    Ich denke jedem ist klar, was ich meine um dies zu ermitteln, ohne Schleife, kann man Bit-Shifting verwenden:


    #include <a_samp>


    main() {
    printf("%d",GetTotalBits(0xF)); //-> 4
    printf("%d",GetTotalBits(10)); //-> 2
    }


    stock GetTotalBits(v) {
    v -= ((v >> 1) & 0x55555555),v = (v & 0x33333333) + ((v >> 2) & 0x33333333);
    return (((v + (v >> 4) & 0xF0F0F0F) * 0x1010101) >> 0x18);
    }


    Kleiner bzw Größer
    Wenn man 2 Variablen hat, x = 13 und y = 14 und prüfen will welche kleiner bzw größer ist, kann man das so machen:


    #define min(%0,%1) (((%0)<(%1))?(%0):(%1))
    #define max(%0,%1) (((%0)>(%1))?(%0):(%1))


    new x = 13, y = 14;
    new r = min(x,y); //r = 13
    new z = max(x,y); //z = 14


    /*
    Man könnte das auch durch Bit-Shifting lösen (da das der Titel ist :D):
    new x = 13, y = 14;
    new r = y ^ ((x ^ y) & -(x < y)); //Das gibt das minimum zurück (13)
    new z = x ^ ((x ^ y) & -(x < y)); //Das gibt das maximum zurück (14)


    Allerdings ist diese Variante wesentlich langsamer, als der ternary Operator :)
    */


    Viel Spaß damit :D


    mfg. :thumbup:

    ast2ufdyxkb1.png


    Leute, lernt scripten und versucht mal lieber etwas selber zu schreiben, als es aus einem GF zu kopieren. :S

  • Diese SWAP Methode ist zwar "schön" (wie man's nimmt), aber nicht wirklich robust. Wenn man die gleiche Variable zwei mal nimmt, kommt 0 raus (logischerweise).
    Beispiel:
    new a=5;
    SWAP(a,a);
    printf("a: %d",a); //Gibt "a: 0" aus.

    Klar, wirklich Sinn macht das nicht, aber nehmen wir mal an, jemand hat einen ziemlich langen Code und irgendwann tritt sowas hier auf (natürlich stark vereinfacht dargestellt):
    new gVar = 10;


    public OnFilterScriptInit()
    {
    EineFunktion(gVar);
    return 1;
    }


    stock EineFunktion(&lVar)
    {
    SWAP(lVar,gVar);
    printf("lVar: %d | gVar: %d",lVar, gVar); //Gibt "lVar: 0 | gVar: 0" aus.
    }
    Hier sieht man es vielleicht noch, aber in komplexen Codes wird man das irgendwann nicht mehr sehen und dann passiert ein Fehler, den der Compiler nicht erkennt. Dann wird es bei der Fehlersuche aber extrem schwer.


    Besser wäre also (wenn man das Zeitliche nicht in Betracht zieht):
    #define SWAP(%0,%1) (%0=(((%0)==(%1))?(%0=%0*1):(((%0)^=(%1)),((%1)^=(%0)),((%0)^=(%1)))))



    Außerdem wird auf sämtlichen Seiten über den Sinn dieser Funktion (mit den Binäroperatoren) diskutiert, da es bei heutigen Prozessoren eigentlich keinen Unterschied mehr macht, ob man es jetzt mit einer Variable macht, oder nicht, da im Endeffekt im Prozessor das gleiche geschieht, bzw. eine Mehrarbeit verrichtet werden muss. Hier ein paar mehr Informationen:
    http://stackoverflow.com/quest…t-way-to-swap-values-in-c
    http://en.wikipedia.org/wiki/X…for_avoidance_in_practice


    Alleine der Satz trifft den Nagel auf den Kopf:

    Zitat

    Number 2 is often quoted as being the "clever" way of doing it. It is in fact most likely slower as it obscures the explicit aim of the programmer - swapping two variables. This means that a compiler can't optimize it to use the actual assembler ops to swap. It also assumes the ability to do a bitwise xor on the objects.


    (Quelle: Stackoverflow Link)



    Jetzt kommt das angesprochene Zeitliche in Betracht. Hier ein Test:
    #define SWAP_K(%0,%1) (((%0)^=(%1)),((%1)^=(%0)),((%0)^=(%1)))
    #define SWAP_J(%0,%1) (%0=(((%0)==(%1))?(%0=%0*1):(((%0)^=(%1)),((%1)^=(%0)),((%0)^=(%1)))))
    #define SWAP_V(%0,%1) (x = %0, %0 = %1, %1 = x)
    new x;

    new a, b, t;


    a = 10; b = 5; t = GetTickCount();
    for(new i=0; i<10000000; i++)
    {
    SWAP_K(a, b);
    }
    printf("Kaliber: %dms", GetTickCount()-t);


    a = 10; b = 5; t = GetTickCount();
    for(new i=0; i<10000000; i++)
    {
    SWAP_J(a, b);
    }
    printf("Jeffry: %dms", GetTickCount()-t);


    a = 10; b = 5; t = GetTickCount();
    for(new i=0; i<10000000; i++)
    {
    SWAP_V(a, b);
    }
    printf("Variable: %dms", GetTickCount()-t);


    Ergebnis:

    Zitat

    [19/02/2015 20:01:34] Kaliber: 637ms
    [19/02/2015 20:01:35] Jeffry: 842ms
    [19/02/2015 20:01:36] Variable: 371ms


    Logisch, dass die robuste Variante von mir langsamer ist, allerdings ist die Variante mit Variable wesentlich schneller. Außerdem kann da der oben angesprochene Fehler mit Verwendung der gleichen Variable nicht passieren, und selbst wenn man es irgendwie hin bekommt wird die Variable nicht auf 0 gesetzt.



    => Sinn macht es also nicht, keine Variable zu verwenden, da es fast doppelt so lange dauert.


  • Musst natürlich das Rad neu erfinden:

    Zitat

    core.inc
    native min(value1, value2);
    native max(value1, value2);


    Zitat

    stock GetTotalBits(v) {
    v -= ((v >> 1) & 0x55555555),v = (v & 0x33333333) + ((v >> 2) & 0x33333333);
    return (((v + (v >> 4) & 0xF0F0F0F) * 0x1010101) >> 0x18);
    }


    Gib doch wenigstens den ursprünglichen Autoren an, zb den hier. Als ob es noch Niemandem aufgefallen wäre, dass hier ständig Sachen von sa-mp.com gepostet werden mit leichter Umstrukturierung (zB Änderungen der Variablennamen, mehrere Anweisungen in 1 Zeilen, Hex Schreibweise anstatt Dezimal).
    Gleiches würde ich auch bei SWAP anmerken.

  • Gib doch wenigstens den ursprünglichen Autoren an, zb den hier. Als ob es noch Niemandem aufgefallen wäre, dass hier ständig Sachen von sa-mp.com gepostet werden mit leichter Umstrukturierung (zB Änderungen der Variablennamen, mehrere Anweisungen in 1 Zeilen, Hex Schreibweise anstatt Dezimal).
    Gleiches würde ich auch bei SWAP anmerken.


    War mir gar nicht bekannt das das schon da gepostet wurde.


    Nein, ich hatte mich auf dieser Seite: https://graphics.stanford.edu/~seander/bithacks.html
    Mal umgeschaut und da ist mir das aufgefallen...


    => Sinn macht es also nicht, keine Variable zu verwenden, da es fast doppelt so lange dauert.


    Das hier ist nicht der Code-Optimierungs Thread :) Bei meinen Beispielen ging es nicht um Speed (wie unten auch angemerkt) wollte lediglich das mal vorstellen, dass diesen "Swap" einige nicht kennen.

    ast2ufdyxkb1.png


    Leute, lernt scripten und versucht mal lieber etwas selber zu schreiben, als es aus einem GF zu kopieren. :S

  • Das macht aber auch nur dann Sinn, wenn man wenig Arbeitsspeicher zur Verfügung hat, was bei SAMP nicht der Fall ist. Man kann für sowas auch eine globale Integer Variable erstellen, die für alle temporären Speichervorgänge verwendet wird, die sich niemals überschneiden, dann muss auch nicht explizit dafür eine Variable erstellt werden. Dann ist es, wie dargestellt, voll funktionsfähig und wesentlich schneller. Und der Code ist auch für Anfänger zu verstehen. Mit den Binäroperatoren fängt nämlich 99% hier nichts an.


    Außerdem ist, wie gesagt, der Code (SWAP) den du gepostet hast fehlerhaft und daher alles andere als nützlich.





    Um nicht unnötig zu posten:
    maddin: (Post unten)
    Nee, das wäre sogar noch besser, da es funktionsfähig und wenigstens gleich performant ist. :D
    :fun:

    3HZXdYd.png

    2 Mal editiert, zuletzt von Jeffry ()

  • ocmd:pn(playerid, params[])
    {
    new sender[MAX_PLAYER_NAME+1];
    GetPlayerName(playerid, sender, sizeof(sender));

    new pID, text[128];
    if(sscanf(params, "us[128]", pID, text)) return SendClientMessage(playerid, COLOR_RED, "INFO: /PN [ID] [TEXT]");
    format(text, 200, "[PN] Spieler %s sagt : '%s'", sender, text);
    SendClientMessage(pID, COLOR_RED, text);
    return 1;
    }


    MfG

  • do.de - Domain-Offensive - Domains für alle und zu super Preisen
  • Naja...das geht aber besser. ;)
    ocmd:pn(playerid, params[])
    {
    new sender[MAX_PLAYER_NAME+1]; //Das +1 brauchst du nicht, da die Namen nur 24 Zeichen haben können und MAX_PLAYER_NAME 24 ist.
    GetPlayerName(playerid, sender, sizeof(sender));


    new pID, text[128]; //Es können 144+1(EOS) Zeichen in SendClientMessage angezeigt werden.
    if(sscanf(params, "us[128]", pID, text)) return SendClientMessage(playerid, COLOR_RED, "INFO: /PN [ID] [TEXT]");
    format(text, 200, "[PN] Spieler %s sagt : '%s'", sender, text); //200 passt hier nicht, du hast es ja nur mit 128 deklariert.
    SendClientMessage(pID, COLOR_RED, text);
    return 1;
    }


    zu:
    ocmd:pn(playerid, params[])
    {
    new sender[MAX_PLAYER_NAME], pID, text[145];
    if(sscanf(params, "us[145]", pID, text)) return SendClientMessage(playerid, COLOR_RED, "INFO: /PN [ID/NAME] [TEXT]");
    GetPlayerName(playerid, sender, sizeof(sender));
    format(text, sizeof(text), "[PN] Spieler %s sagt : '%s'", sender, text);
    return SendClientMessage(pID, COLOR_RED, text);
    }

    3HZXdYd.png

    Einmal editiert, zuletzt von Jeffry () aus folgendem Grund: 20 -> 24

  • new sender[MAX_PLAYER_NAME+1]; //Das +1 brauchst du nicht, da die Namen nur 20 Zeichen haben können und MAX_PLAYER_NAME 24 ist.


    Im Grunde hast du recht, ABER die Namen können auch 24 Zeichen lang werden, Grund ist hier SetPlayerName, welches erlaubt dem Namen 24 Zeichen zu geben.


    Nützlich ist sowas bspw. wenn man einen "Tag" beim Connecten davor setzt.

    Player names can be up to 24 characters when using this function,
    but when joining the server from the SA-MP server browser,
    players' names must be no more than 20 and less than 3 characters (the server will deny entry).
    This allows for 4 characters extra when using SetPlayerName.

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

    Margarete Stokowski

  • Im Grunde hast du recht, ABER die Namen können auch 24 Zeichen lang werden, Grund ist hier SetPlayerName, welches erlaubt dem Namen 24 Zeichen zu geben.


    Oh, ja stimmt. Hatte ich verdrängt, Danke für den Hinweis.
    Allerdings spielt das auch keine Rolle, da MAX_PLAYER_NAME 24 ist, und da passen die 24 Buchstaben vom Spieler-Name rein. Ein +1 ist also trotzdem nicht unbedingt notwendig.


    Habe dennoch meinen Kommentar natürlich angepasst.

  • Ich hab gerade mal einen Code geschrieben um einen String zu verschlüsseln und dann wieder zu entschlüsseln.


    Im Prinzip nichts großartiges, doch wenn man in einer Datei z.B. etwas speichern will, was nicht jeder lesen soll und aber trotzdem wieder im Klartext haben will, ist es ganz praktisch:


    static stock const c_v[] = { 0xFBCAE, 0xDFC, 0xA8D, 0xAFECB };


    stock Crypt(string[]) {
    for(new i,l=strlen(string),tmp[2]; i<l; i++) {
    format(tmp,sizeof tmp,"%c",string[i]+c_v[0]+(c_v[1]*c_v[2])+c_v[3]+(l*i));
    string[i] = tmp[0];
    }
    return 1;
    }


    stock DeCrypt(string[]) {
    for(new i,l=strlen(string),tmp[2]; i<l; i++) {
    format(tmp,sizeof tmp,"%c",string[i]-c_v[0]-(c_v[1]*c_v[2])-c_v[3]-(l*i));
    string[i] = tmp[0];
    }
    return 1;
    }


    Hier ein Beispiel:


    new string[] = "Hallo Welt";
    Crypt(string);
    print(string);
    DeCrypt(string);
    print(string);


    Das sieht dann so aus:



    //Edit:
    Hier nochmal ein paar mehr Beispiele:




    Also, viel Spaß damit :)


    //Edit²: Rechtschreibfehler


    mfg. :thumbup:

    ast2ufdyxkb1.png


    Leute, lernt scripten und versucht mal lieber etwas selber zu schreiben, als es aus einem GF zu kopieren. :S

    2 Mal editiert, zuletzt von Kaliber ()

  • EmptyVehicle


    Quellcode
    stock EmptyVehicle(vID)
    {
    for(new i=0, yourvID; i < GetMaxPlayers(); i++)
    {
    if(IsPlayerConnected(i) && !IsPlayerNPC(i))
    {
    if(IsPlayerInAnyVehicle(i))
    {
    yourvID = GetPlayerVehicleID(i);
    if(yourvID == vID)return 0;
    }
    }
    }
    return 1;
    }


    Verwendung
    if(EmtpyVehicle(vID)) //Fahrzeug ist leer.


    mfg :thumbup:

  • Und was ist wenn ein NPC in diesem Fahrzeug ist? Falls man es löschen will, dann hätte der NPC keins mehr.


    Du kannst es viel einfacher so schreiben:
    stock EmptyVehicle(vID)
    {
    for(new i=0, j=GetMaxPlayer(); i<j; i++) if(IsPlayerInVehicle(i, vID)) return 0;
    return 1;
    }

  • Eine Funktion um ein SendClientMessage mit "Variablen" ohne ihn neu formatieren zu müssen:



    Kaliber:
    Ich hoffe das war O.K das ich das hier poste,
    ist ne nützliche Funktion die der ein oder andere bestimmt gebrauchen kann.

  • Ich hab gerade was interessantes herausgefunden.


    Ihr kennt ja alle folgendes:


    forward func();
    public func()
    {
    print("hi");
    return 1;
    }


    Wenn man das aber abgrenzen will in einer Include z.B. und dort per Timer aufrufen will, aber nicht im Gamemode, kann man folgendes machen:


    static func();
    public func()
    {
    print("hi");
    return 1;
    }
    So kann man also quasi static als forward nutzen :)


    Übrigens für die, die es noch nicht wussten, in Pawn gibt es auch totale public Variablen:


    public x = 5;


    main()
    {
    printf("%d",x); //-> 5
    }


    Das ist eigentlich nur für Plugins relevant und macht keinen unterschied zur normalen "new" Deklaration in diesem Sinne.


    mfg. :thumbup:

    ast2ufdyxkb1.png


    Leute, lernt scripten und versucht mal lieber etwas selber zu schreiben, als es aus einem GF zu kopieren. :S