Beiträge von Jeffry

    Das ist keine kleine Scripting Frage. Dieser Thread ist nicht für MySQL Debugging gedacht. Merke dir das bitte für das nächste Mal und erstelle dann einen Thread. Danke! :)


    Teste es mal so:

    Spoiler anzeigen
    stock LoadWeapons(playerid)
    {
    new query[256];
    format(query,sizeof(query),"SELECT * FROM Waffen WHERE Name='%s'",PlayerName[playerid]);
    mysql_query(query);
    mysql_store_result();

    new wstring[10],data[64];
    new waffe, wammo;

    if(mysql_num_rows()==0)
    {
    mysql_free_result();
    format(query,sizeof(query),"INSERT INTO Waffen (Name) VALUES ('%s')",PlayerName[playerid]);
    mysql_query(query);
    return 1;
    }
    for(new i=1; i<=11; i++)
    {
    format(wstring,sizeof(wstring),"Waffe%i",i);
    mysql_fetch_field_row(data,wstring);
    waffe=strval(data);
    format(wstring,sizeof(wstring),"Ammo%i",i);
    mysql_fetch_field_row(data,wstring);
    wammo=strval(data);
    GivePlayerWeapon(playerid,waffe,wammo);
    format(str,144,"UPDATE Waffen SET Ammo%i='0' WHERE Name='%s'",i,PlayerName[playerid]);
    mysql_query(str);
    }
    mysql_fetch_field_row(data,"Armor");
    mysql_free_result();
    wammo=strval(data);
    SetPlayerArmour(playerid,wammo);
    SetPVarInt(playerid,"waffengeladen",1);
    return 1;
    }

    Wenn es nicht geht, poste den MySQL Log.

    Es könnte sein, dass die Variable nicht richtig gesetzt ist (Pickup ID 0?).
    Schreib das mal bei OnPlayerConnect hin:
    for(new i=0; i<MAX_ANPFLANZEN; i++) drogenpickup[playerid][i] = -1;
    Wenn es dann trotzdem nicht geht, müssen wir das mal debuggen.

    Naja, ich glaube nicht, dass er damit viel anfängt, das ist ja nur ein Zähler, der hier gar nichts bringt, denn er kann die fertigen Drogen ja in unterschiedlicher Reigenfolge abholen. ;)



    Grundsätzlich geht es ja darum, einen Code zu haben, der für alle X erlaubten "Anpflanzungen" das gleiche macht. Das wird über ein entsprechendes Array gemacht (wir fügen einfach "[MAX_ANPFLANZEN]" hinter den Variablen an, bei der Deklaration.
    Außer bei den zwei markierten, denn dies sind Zähler, die für alle X entsprechend sind.


    #define MAX_ANPFLANZEN 10
    enum drogenenum
    {
    Float:dX,
    Float:dY,
    Float:dZ,
    }
    //new´s
    new dInfo[MAX_PLAYERS][MAX_ANPFLANZEN][drogenenum];
    new drogentimer[MAX_PLAYERS][MAX_ANPFLANZEN];
    new drogenstatus[MAX_PLAYERS][MAX_ANPFLANZEN];
    new drogensamen[MAX_PLAYERS]; //Hier nicht!
    new drogenpickup[MAX_PLAYERS][MAX_ANPFLANZEN];
    new drogenobject[MAX_PLAYERS][MAX_ANPFLANZEN];
    new Text3D:drogentext[MAX_PLAYERS][MAX_ANPFLANZEN];
    new drogenprozent[MAX_PLAYERS][MAX_ANPFLANZEN];
    new angepflanzteDrogen[MAX_PLAYERS]; //Hier nicht!



    Der Befehl würde dann so aussehen:


    ocmd:anpflanzen(playerid,params[])
    {
    if(drogensamen[playerid] < 1)return SendClientMessage(playerid,C_Error,"Du hast keine Drogensamen!");
    if(GetPlayerInterior(playerid)==0)
    {
    new id = GetFreeDrogenID(playerid); //Wir brauchen diese Funktion um einen freien Index zu finden
    if(id == -1)return SendClientMessage(playerid,C_Error,"Du kannst keine Drogen mehr anpflanzen, ernte erst welche ab!");
    new Float:x,Float:y,Float:z,Float:r;
    GetPlayerPos(playerid,x,y,z);
    GetPlayerFacingAngle(playerid, Float:r);
    dInfo[playerid][id][dX]=x;
    dInfo[playerid][id][dY]=y;
    dInfo[playerid][id][dZ]=z;
    drogenobject[playerid][id]=CreateObject(647, dInfo[playerid][id][dX], dInfo[playerid][id][dY], dInfo[playerid][id][dZ]-1.2, 0.0, 0.0, r);
    drogentext[playerid][id]=Create3DTextLabel("0 %",C_Weiß,dInfo[playerid][id][dX],dInfo[playerid][id][dY],dInfo[playerid][id][dZ],10.0,0,0);
    SendClientMessage(playerid,C_Gruen,"Du hast 1 Drogenpflanze angebaut.");
    drogenprozent[playerid][id]=0;
    drogenstatus[playerid][id] = 1; //Diese Droge ist nun erstellt.
    drogentimer[playerid][id]=SetTimerEx("DrogenWachsTimer",1000,1,"ii",playerid,id); //Auch im Timer die id mitgeben.
    angepflanzteDrogen[playerid]++;
    return 1;
    }
    else
    {
    SendClientMessage(playerid,C_Error,"Du kannst keine Drogen im Interior anpflanzen!");
    }
    return 1;
    }


    Hier unsere GetFreeDrogenID Funktion, einfach ganz unten im Gamemode einfügen.


    stock GetFreeDrogenID(playerid)
    {
    for(new i=0; i<MAX_ANPFLANZEN; i++)
    {
    if(drogenstatus[playerid][i] == 0) return i;
    }
    return -1;
    }



    Und dann dein Timer-Callback:


    forward DrogenWachsTimer(playerid, id);
    public DrogenWachsTimer(playerid, id)
    {
    if(drogenprozent[playerid][id]==100)
    {
    DestroyObject(drogenobject[playerid][id]);
    drogenpickup[playerid][id]=CreatePickup(19473,1,dInfo[playerid][id][dX],dInfo[playerid][id][dY],dInfo[playerid][id][dZ],GetPlayerVirtualWorld(playerid));
    KillTimer(drogentimer[playerid][id]);
    Delete3DTextLabel(drogentext[playerid][id]);
    drogenstatus[playerid][id] = 2; //Droge ist fertig.
    }
    else
    {
    new str[10];
    drogenprozent[playerid][id]++;
    format(str,sizeof(str),"%i %%",drogenprozent[playerid][id]);
    Update3DTextLabelText(drogentext[playerid][id],C_Weiß,str);
    }
    return 1;
    }



    Dort wo du dir Drogen aufsammelst muss dann natürlich das Pickup entfernt werden, und die Variablen zurückgesetzt werden:
    drogenprozent[playerid][id] = 0;
    drogenstatus[playerid][id] = 0; //Slot wieder frei
    angepflanzteDrogen[playerid]--;


    Die Prüfung, in welches Pickup, also in welche fertige Droge du läufst, sieht so aus:
    for(new i=0; i<MAX_ANPFLANZEN; i++)
    {
    if(pickupid == drogenpickup[playerid][i])
    {
    //Hier käme dann der Code aus dem Code drüber hin:
    drogenprozent[playerid][i] = 0;
    drogenstatus[playerid][i] = 0; //Slot wieder frei
    angepflanzteDrogen[playerid]--;
    //Und dann eben noch das was du sonst hier machen willst...

    //Schleife wird beendet.
    break;
    }
    }


    Außerdem musst du die Drogen natürlich löschen, wenn der Spieler den Server verlässt. Da kannst du einfach über den Status abfragen, was gelöscht werden soll:
    for(new i=0; i<MAX_ANPFLANZEN; i++)
    {
    if(drogenstatus[playerid][i] == 1)
    {
    DestroyObject(drogenobject[playerid][i]);
    KillTimer(drogentimer[playerid][i]);
    Delete3DTextLabel(drogentext[playerid][i]);
    }
    else if(drogenstatus[playerid][i] == 2)
    {
    DestroyPickup(drogenpickup[playerid][i]);
    }
    drogenstatus[playerid][i] = 0;
    }
    angepflanzteDrogen[playerid] = 0;



    Generell ist es einfach das gleiche Prinzip wie zuvor, nur eben mit dem Slot-Index überall dabei.

    Das mit dem Zeilenumbruch kannst du nur bei den Parametern hinten machen, das würde hier wahrscheinlich sogar noch gehen. Dein string (das rote) darf halt nicht länger als die maximal erlaubt Zeilen Länge sein.


    format(statstring,sizeof(statstring),"Spielzeit: %d, Payday: %d\nGeld: %d, Bank: %d\nFraktion: %d, Leader: %d\nMember: %d, Job: %d\nHandyNr.: %d, HandyGuthaben: %d$\nLevel: %d, Admin: %d\nWeiteres Folgt...",
    pInfo[playerid][spielzeitinsgesamt],pInfo[playerid][paydayzeit],GetPlayerMoney(playerid),pInfo[playerid][Bank],pInfo[playerid][Fraktion],
    pInfo[playerid][Leader],pInfo[playerid][Member],pInfo[playerid][Job],pInfo[playerid][Handy],pInfo[playerid][HandyGuthaben], GetPlayerScore(playerid), pInfo[playerid][AdminLevel]);


    Ansonsten, und das ist die bessere Variante hinsichtlich Übersicht:
    format(statstring,sizeof(statstring),"Spielzeit: %d, Payday: %d\nGeld: %d, Bank: %d\nFraktion: %d, ",pInfo[playerid][spielzeitinsgesamt],pInfo[playerid][paydayzeit],GetPlayerMoney(playerid),pInfo[playerid][Bank],pInfo[playerid][Fraktion]);
    format(statstring,sizeof(statstring),"%sLeader: %d\nMember: %d, Job: %d\nHandyNr.: %d, HandyGuthaben: %d$",statstring, pInfo[playerid][Leader],pInfo[playerid][Member],pInfo[playerid][Job],pInfo[playerid][Handy],pInfo[playerid][HandyGuthaben]);
    format(statstring,sizeof(statstring),"%s\nLevel: %d, Admin: %d\nWeiteres Folgt...",statstring, GetPlayerScore(playerid), pInfo[playerid][AdminLevel]);


    Klar wird die Zeile auch wieder lang, aber wahrscheinlich nicht zu lang. Außerdem kannst du das so ja auch auf 20 Zeilen aufteilen, das geht auch.

    Das liegt daran, dass SendClientMessageToAll und SendClientMessage nur maximal 144 Zeichen ausgeben können (plus EOS).


    Schreibe deine Deklarationen so, dann siehst du ab wann es abgeschnitten wird, mehr kann nicht angezeigt werden.
    new pID,fID,string[145];

    Ok, dann so:
    Unter den Includes (global):
    new onlinePlayers;
    new onlineTimer = -1;


    OnPlayerDisconnect:
    onlinePlayers--;
    if(onlinePlayers == 1) if(onlineTimer != -1) KillTimer(onlineTimer), onlineTimer = -1;


    OnPlayerConnect:
    onlinePlayers++;
    if(onlinePlayers == 2) onlineTimer = SetTimer("ZweiSpielerJetzt", 120000, false); //120 sek = 2 min = 120.000 Millisekunden


    Und das Callback:
    forward ZweiSpielerJetzt();
    public ZweiSpielerJetzt();
    {
    onlineTimer = -1;
    //Mach was hier...
    return 1;
    }

    Ok.


    Soll es ein Limit pro Spieler geben, oder ein Limit im Server?
    Also jeder Spieler kann maximal zum Beispiel 10 gleichzeitig anpflanzen, oder im Server dürfen gleichzeitig maximal zum Beispiel 100 Drogen angepflanzt werden, egal von wem?
    Wie soll es sein?

    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:

    Wir sollten es mal den SA-MP Entwicklern sagen das es ein Plugin BZW eine Modifikation´s Sperre eingefügt wird, die dann Mod´s die man einfügt gesperrt werden für den Server das wär praktisch den fast jeder Server mag MIN 1 Mod nicht auf dem Server haben!


    Und dafür postest du in einem 4,5 Jahre alten Thread? :huh:


    Übrigens:
    Das wird nichts bringen, denn das kann man natürlich auch umgehen, wenn man will.


    Ach ja, dem SA-MP Entwickler brauch man gar nichts sagen, das hat eh keinen Sinn. Da spricht man gegen eine Wand, der behebt ja nicht mal Bugs die seit 5 Jahren und mehr existieren. ;)

    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.

    MoveObject(govbarrier1,1284.22388, -2059.59863, 58.5415, 0.0001, 0.00000, 0.00000, 90.00000);


    Man muss die Position ein kleines Bisschen ändern (hier hab ich das Z geändert).