Beiträge von Manyula

    Hallo,


    wie der Titel bereits schon sagt geht es um ein Login & Register System, basierend auf Y_INI.


    Das hier ist die Funktion, die die Spielerdaten lädt, mitsamt Define für den Pfad und dem dazugehörigen enum mit der Variable, die darauf zugreift.
    #define UserPath "Users/%s.ini"


    enum PlayerInfo
    {
    Password[129],
    IP[16],
    bool:JustLoggedIn, //doesn't need to be saved
    bool:JustRegistered, //doesn't need to be saved
    AdminLevel,
    Money,
    Bank,
    Score,
    Kills,
    Deaths,
    Language,
    bool:Desynced
    }


    new pInfo[MAX_PLAYERS][PlayerInfo];


    forward loadaccount_user(playerid, name[], value[]);
    public loadaccount_user(playerid, name[], value[])
    {
    print("loadaccount_user executed."); //Debug Line
    INI_String("Password", pInfo[playerid][Password], 129);
    INI_String("IP", pInfo[playerid][IP], 16);
    INI_Int("AdminLevel", pInfo[playerid][AdminLevel]);
    INI_Int("Money", pInfo[playerid][Money]);
    INI_Int("Bank", pInfo[playerid][Bank]);
    INI_Int("Score", pInfo[playerid][Score]);
    INI_Int("Kills", pInfo[playerid][Kills]);
    INI_Int("Deaths", pInfo[playerid][Deaths]);
    INI_Int("Language", pInfo[playerid][Language]);
    return 1;
    }


    Folgendes steht unter OnPlayerDisconnect. (Das ganze ist gehookt)
    public OnPlayerDisconnect(playerid, reason)
    {
    print("OnPlayerDisconnect executed."); //Debug Line
    new INI:file = INI_Open(Path(playerid));
    INI_SetTag(file, "User Data");
    INI_WriteString(file, "IP", pInfo[playerid][IP]);
    INI_WriteInt(file, "AdminLevel", pInfo[playerid][AdminLevel]);
    INI_WriteInt(file, "Money", GetPlayerMoney(playerid));
    INI_WriteInt(file, "Bank", pInfo[playerid][Bank]);
    INI_WriteInt(file, "Score", GetPlayerScore(playerid));
    INI_WriteInt(file, "Kills", pInfo[playerid][Kills]);
    INI_WriteInt(file, "Deaths", pInfo[playerid][Deaths]);
    INI_WriteInt(file, "Language", pInfo[playerid][Language]);
    INI_Close(file);
    return SAVE_OnPlayerDisconnect(playerid, reason);
    }


    forward SAVE_OnPlayerDisconnect(playerid, reason);
    #if defined _ALS_OnPlayerDisconnect
    #undef OnPlayerDisconnect
    #else
    #define _ALS_OnPlayerDisconnect
    #endif
    #define OnPlayerDisconnect SAVE_OnPlayerDisconnect


    Alle Spielerdaten werden jeweils beim Connect, DIsconnect, sowie beim Login-Dialog und Register-Dialog mittels
    INI_ParseFile(Path(playerid), "loadaccount_%s", .bExtra = true, .extra = playerid);
    abgerufen.


    Was noch von Relevanz sein könnte, wären die zwei Callbacks hier aus dem Main Script.
    public OnPlayerSpawn(playerid)
    {
    SetPlayerColor(playerid, C_BLUE);


    new VirtualWorld = GetPlayerVirtualWorld(playerid);
    switch(VirtualWorld)
    {
    case 0:
    {
    print("The player is in the virtual world 0. Proceed with the code."); //Debug Line
    if(pInfo[playerid][JustLoggedIn] == true)
    {
    print("JustLoggedIn == true, executing code."); //Debug Line
    SetCameraBehindPlayer(playerid);
    GivePlayerMoneyEx(playerid, pInfo[playerid][Money]);
    SetPlayerScore(playerid, pInfo[playerid][Score]);
    pInfo[playerid][JustLoggedIn] = false;
    }
    else if(pInfo[playerid][JustLoggedIn] == false)
    {
    print("JustLoggedIn == false, executing code."); //Debug Line
    GivePlayerMoneyEx(playerid, 5000);
    }
    if(pInfo[playerid][JustRegistered] == true)
    {
    print("JustRegistered == true, executing code."); //Debug Line
    cmd_rules(playerid, "");
    pInfo[playerid][JustRegistered] = false;
    GivePlayerMoneyEx(playerid, 5000);
    }
    print("UseTeleports = true, Spawnprotection set."); //Debug Line
    UseTeleports[playerid] = true;
    SetSpawnProtection(playerid);
    }
    }
    return 1;
    }


    public OnPlayerDeath(playerid, killerid, reason)
    {
    SendDeathMessage(killerid, playerid, reason);

    new cash = GetPlayerMoney(playerid);
    if(killerid != INVALID_PLAYER_ID) //Killed by another player
    {
    GivePlayerMoneyEx(killerid, cash);
    GivePlayerMoneyEx(playerid, -cash);
    pInfo[killerid][Score] += 1;
    pInfo[killerid][Kills] += 1;
    }
    if(killerid == INVALID_PLAYER_ID) //Suicide
    {
    GivePlayerMoneyEx(playerid, -cash);
    }
    pInfo[playerid][Deaths] += 1;
    return 1;
    }


    Das ganze passiert, seit ich auf die YSI 4.0 Beta aufgestockt habe.


    ___________________________________________________________________________________________________________________________________________


    EDIT: Ich habe den Code mit den Debug Nachrichten geupdated. Hier ist, was in der Console ausgegeben wird.

    Code
    [13:45:03] Incoming connection: 127.0.0.1:56637
    [13:45:03] [join] Test has joined the server (0:127.0.0.1)
    [13:45:05] Parsing Userfile.
    [13:45:07] The player is in the virtual world 0. Proceed with the code.
    [13:45:07] JustLoggedIn == true, executing code.
    [13:45:07] UseTeleports = true, Spawnprotection set.
    [13:45:13] OnPlayerDisconnect executed.
    [13:45:13] [part] Test has left the server (0:1)

    Ich möchte mal ein ganz arg großes Lob aussprechen, und zwar an (wen wunderts) Jeffry. Jeffry hat sich auf meine Bitte hin die Mühe gemacht ein (für mich) äußerst aufwändiges Tutorial zu schreiben. Zudem ist er stehts hilfsbereit, liefert immerzu kompetente und problemkonforme Antworten und gibt auch nicht auf, wenn man mal etwas nicht versteht. Weiter so, Jeffry!

    Wunderbar, nun werden sie angezeigt! :)


    Bleibt noch ein Problem. Folgender Code ist ein riesiges Durcheinander, da ich hier und da etwas neu geschrieben habe und auch noch altes hab stehen lassen.


    stock UpdateLanguageLabels(playerid)
    {
    if(pInfo[playerid][Language] == LANGUAGE_DE)
    {
    UpdateDynamic3DTextLabelText(TeleportLabel[playerid][16], C_PURPLE, "» Teleport «\n"#C_WHITE_E"San Fierro Denkmal\n/SFD");
    UpdateDynamic3DTextLabelText(TeleportLabel[playerid][23], C_PURPLE, "» Teleport «\n"#C_WHITE_E"The Big Ear Satellit Station\n/Satellit");
    UpdateDynamic3DTextLabelText(TeleportLabel[playerid][24], C_PURPLE, "» Teleport «\n"#C_WHITE_E"Verlassener Flughafen\n/VF");
    UpdateDynamic3DTextLabelText(TeleportLabel[playerid][27], C_PURPLE, "» Teleport «\n"#C_WHITE_E"Geistersee\n/GS");

    for(new i = 0; i < MAX_GANG_ZONES; i++)
    {
    for(new g = 0; g < MAX_PLAYERS; g++)
    {
    new string[128];
    format(string, sizeof(string), "» GANG ZONE «\n"#C_WHITE_E"ID: %i\n%s", i, GW_Name[i][0]);
    DestroyDynamic3DTextLabel(GangZoneLabel[g][i]);
    CreateDynamic3DTextLabel(string, C_ORANGE, GW_CaptureCPs[i][0], GW_CaptureCPs[i][1], GW_CaptureCPs[i][2], 100.0, g, INVALID_VEHICLE_ID, 1, 0, -1, -1, 100.0);
    }
    }
    }
    if(pInfo[playerid][Language] == LANGUAGE_EN)
    {
    UpdateDynamic3DTextLabelText(TeleportLabel[playerid][16], C_PURPLE, "» Teleport «\n"#C_WHITE_E"San Fierro Memorial\n/SFM");
    UpdateDynamic3DTextLabelText(TeleportLabel[playerid][23], C_PURPLE, "» Teleport «\n"#C_WHITE_E"The Big Ear Satellite Station\n/Satellite");
    UpdateDynamic3DTextLabelText(TeleportLabel[playerid][24], C_PURPLE, "» Teleport «\n"#C_WHITE_E"Abandoned Airport\n/AA");
    UpdateDynamic3DTextLabelText(TeleportLabel[playerid][27], C_PURPLE, "» Teleport «\n"#C_WHITE_E"Ghost Lake\n/GL");


    for(new i = 0; i < MAX_GANG_ZONES; i++)
    {
    for(new g = 0; g < MAX_PLAYERS; g++)
    {
    new string[128];
    format(string, sizeof(string), "» GANG ZONE «\n"#C_WHITE_E"ID: %i\n%s", i, GW_Name[i][1]);
    DestroyDynamic3DTextLabel(GangZoneLabel[g][i]);
    CreateDynamic3DTextLabel(string, C_ORANGE, GW_CaptureCPs[i][0], GW_CaptureCPs[i][1], GW_CaptureCPs[i][2], 100.0, g, INVALID_VEHICLE_ID, 1, 0, -1, -1, 100.0);
    }
    }
    }
    return 1;
    }


    Wie unschwer zu erkennen ist, möchte ich die TeleportLabel auch "updaten", jedoch nicht alle, sondern nur die ausgewählten: 16, 23, 24 und 27, also lohnt sich ein Loop nicht. Muss ich diese bei einem Sprachwechsel dann einfach zerstören und neu erstellen, oder wie stelle ich das an?

    public OnGameModeInit()
    {
    new string[80];
    for(new i = 0; i < MAX_GANG_ZONES; i++)
    {
    GangZone[i] = GangZoneCreate(GW_ZoneCoordinates[i][0], GW_ZoneCoordinates[i][1], GW_ZoneCoordinates[i][2], GW_ZoneCoordinates[i][3]);
    for(new g = 0; g < MAX_PLAYERS; g++)
    {
    format(string, sizeof(string), "» GANG ZONE «\n"#C_WHITE_E"ID: %i\n%s", i, GW_Name[i][0]);
    GangZoneLabel[g][i] = CreateDynamic3DTextLabel(string, C_ORANGE, GW_CaptureCPs[i][0], GW_CaptureCPs[i][1], GW_CaptureCPs[i][2], 100.0, g, INVALID_VEHICLE_ID, 1, 0, -1, -1, 100.0);
    }
    }
    return GANG_OnGameModeInit();
    }


    forward GANG_OnGameModeInit();
    #if defined _ALS_OnGameModeInit
    #undef OnGameModeInit
    #else
    #define _ALS_OnGameModeInit
    #endif
    #define OnGameModeInit GANG_OnGameModeInit


    Das hier ist der aktuelle Code. Wie gesagt, die Zone wird erstellt, aber scheinbar kommt der Compiler nicht an die verschachtelte MAX_PLAYER Schleife.


    PS: Danke, für deine Hilfsbereitschaft! :thumbup:

    Folgender Code...
    public OnGameModeInit()
    {
    new string[80];
    for(new i = 0; i < MAX_GANG_ZONES; i++)
    {
    GangZone[i] = GangZoneCreate(GW_ZoneCoordinates[i][0], GW_ZoneCoordinates[i][1], GW_ZoneCoordinates[i][2], GW_ZoneCoordinates[i][3]);
    for(new g = 0; g < MAX_PLAYERS; g++)
    {
    format(string, sizeof(string), "» GANG ZONE «\n"#C_WHITE_E"ID: %i\n%s", i, GW_Name[i][0]);
    GangZoneLabel[g][i] = CreateDynamic3DTextLabel(string, C_ORANGE, GW_CaptureCPs[i][0], GW_CaptureCPs[i][1], GW_CaptureCPs[i][2], 100.0, g, INVALID_VEHICLE_ID, 1, 0, -1, -1, 100.0); //Tag Mismatch
    }
    }
    return GANG_OnGameModeInit();
    }


    ...liefert einen tag mismatch bei Erstellen des Labels.


    EDIT: Ich habe "PlayerText3D" zu "Text3D" umgeschrieben. Jetzt spuckt er zumindest keine Warnings oder Errors mehr aus.

    Also, im Klartext bedeutet das dann das hier?


    new PlayerText3D:GangZoneLabel[MAX_PLAYERS][MAX_GANG_ZONES];


    public OnGameModeInit()
    {
    new string[80];
    for(new i = 0; i < MAX_GANG_ZONES; i++)
    {
    GangZone[i] = GangZoneCreate(GW_ZoneCoordinates[i][0], GW_ZoneCoordinates[i][1], GW_ZoneCoordinates[i][2], GW_ZoneCoordinates[i][3]);
    for(new g = 0; g < MAX_PLAYERS; g++)
    {
    format(string, sizeof(string), "» GANG ZONE «\n"#C_WHITE_E"ID: %i\n%s", i, GW_Name[i][0]);
    GangZoneLabel[g][i] = CreateDynamic3DTextLabel(string, C_ORANGE, GW_CaptureCPs[i][0], GW_CaptureCPs[i][1], GW_CaptureCPs[i][2], 100.0, INVALID_PLAYER_ID, INVALID_VEHICLE_ID, 1, 0, -1, -1, 100.0);
    }
    }
    return GANG_OnGameModeInit();
    }

    1. Du brauchst hier keine Abfrage, ob der Spieler connected ist. Wenn ein Spieler den CMD eingibt, ist er zwangsweise ja online.
    2. Ich sehe hier nur, dass du irgendwelche ClientMessages ausgibst. Wenn du einen Godmode für Fahrzeuge erstellen willst, dann stürz dich mal auf SetTimerEx. ;)

    public OnGameModeInit()
    {
    new string[80];
    for(new i = 0; i < MAX_GANG_ZONES; i++)
    {
    format(string, sizeof(string), "» GANG ZONE «\n"#C_WHITE_E"ID: %i\n%s", i, GW_Name[i][0]);
    GangZoneLabel[i] = CreateDynamic3DTextLabel(string, C_ORANGE, GW_CaptureCPs[i][0], GW_CaptureCPs[i][1], GW_CaptureCPs[i][2], 100.0, INVALID_PLAYER_ID, INVALID_VEHICLE_ID, 1, 0, -1, -1, 100.0);
    GangZone[i] = GangZoneCreate(GW_ZoneCoordinates[i][0], GW_ZoneCoordinates[i][1], GW_ZoneCoordinates[i][2], GW_ZoneCoordinates[i][3]);
    }
    return GANG_OnGameModeInit();
    }


    Wie stelle ich das dann hier am besten an? Ich brauche einerseits einen Loop durch MAX_PLAYERS dann um das Label für playerid zu erstellen, aber andererseits auch einen Loop durch MAX_GANG_ZONES, um die korrekte Anzahl an Zonen mit den entsprechenden IDs zu erstellen.

    Das Problem ist dann eben nur noch, dass ich keinen "playerid" Parameter in DestroyDynamic3DTextLabel habe, der das Label nur für den einen Spieler zerstört. Ich hoffe, mein Problem ist nun etwas verständlicher... :S


    Edit: Hier einmal der Code, wie ich es mit dem Updatedn anstelle.


    stock UpdateLanguageLabels(playerid)
    {
    if(pInfo[playerid][Language] == LANGUAGE_DE)
    {
    UpdateDynamic3DTextLabelText(TeleportLabel[16], C_PURPLE, "» Teleport «\n"#C_WHITE_E"San Fierro Denkmal\n/SFD");
    UpdateDynamic3DTextLabelText(TeleportLabel[23], C_PURPLE, "» Teleport «\n"#C_WHITE_E"The Big Ear Satellit Station\n/Satellit");
    UpdateDynamic3DTextLabelText(TeleportLabel[24], C_PURPLE, "» Teleport «\n"#C_WHITE_E"Verlassener Flughafen\n/VF");
    UpdateDynamic3DTextLabelText(TeleportLabel[27], C_PURPLE, "» Teleport «\n"#C_WHITE_E"Geistersee\n/GS");

    for(new i = 0; i < sizeof(GW_Name); i++)
    {
    new string[128];
    format(string, sizeof(string), "» GANG ZONE «\n"#C_WHITE_E"ID: %i\n%s", i, GW_Name[i][0]);
    UpdateDynamic3DTextLabelText(GangZoneLabel[i], C_ORANGE, string);
    }
    }
    if(pInfo[playerid][Language] == LANGUAGE_EN)
    {
    UpdateDynamic3DTextLabelText(TeleportLabel[16], C_PURPLE, "» Teleport «\n"#C_WHITE_E"San Fierro Memorial\n/SFM");
    UpdateDynamic3DTextLabelText(TeleportLabel[23], C_PURPLE, "» Teleport «\n"#C_WHITE_E"The Big Ear Satellite Station\n/Satellite");
    UpdateDynamic3DTextLabelText(TeleportLabel[24], C_PURPLE, "» Teleport «\n"#C_WHITE_E"Abandoned Airport\n/AA");
    UpdateDynamic3DTextLabelText(TeleportLabel[27], C_PURPLE, "» Teleport «\n"#C_WHITE_E"Ghost Lake\n/GL");


    for(new i = 0; i < sizeof(GW_Name); i++)
    {
    new string[128];
    format(string, sizeof(string), "» GANG ZONE «\n"#C_WHITE_E"ID: %i\n%s", i, GW_Name[i][1]);
    UpdateDynamic3DTextLabelText(GangZoneLabel[i], C_ORANGE, string);
    }
    }
    return 1;
    }

    Hallo,


    ich habe gerade ein ziemlich großes Problem. Und zwar frage ich mich, ob es möglich ist 3D Text Labels spezifisch für einen Spieler erscheinen zu lassen und ebenso spezifisch für einen Spieler zu zerstören.
    Ich habe eine Fülle an 3D Text Labels erstellt, die je nach Spracheinstellung ihren Inhalt wechseln (Deutsch & Englisch). Mit UpdateDynamic3DTextLabel kann ich nicht arbeiten, da es den Text aller Labels für alle Spieler updatet, und das ist ja genau das, was ich nicht will. Hat jemand eine alternative Lösung? Hat es etwas wie "Create3DTextLabelForPlayer", "Destroy3DTextLabelForPlayer" oder "Update3DTextLabelForPlayer"?


    Grüße,


    Many

    Ich bin davon ausgegangen, dass der Parameter "attachedplayer" dafür sorgt, dass es an einen Spieler, hier "playerid", geknüpft wird.
    Also muss ich extra nochmal Attach3DTextLabelToPlayer benutzen?
    Eine Chatbubble ist nicht das, was ich suche. ;)

    Hallöchen Brötchen,


    folgendes Player3DTxetLabel soll erscheinen, solange die Spawnprotection aktiv ist. Leider wird dabei nichts angezeigt. Wo liegt mein Denkfehler?


    new PlayerText3D:SpawnProtectionInfo[MAX_PLAYERS];


    stock SetSpawnProtection(playerid)
    {
    SpawnProtectionInfo[playerid] = CreatePlayer3DTextLabel(playerid, "SPAWN PROTECTION", C_RED, 0.0, 0.0, 0.0, 50.0, playerid, INVALID_VEHICLE_ID, 0);

    if(GetPlayerVirtualWorld(playerid) == 0) SetTimerEx("EndSpawnProtection", 3000, false, "i", playerid);
    else //...
    return 1;
    }


    forward EndSpawnProtection(playerid);
    public EndSpawnProtection(playerid)
    {
    DeletePlayer3DTextLabel(playerid, SpawnProtectionInfo[playerid]);
    return 1;
    }

    Wenn du nichts ausgeben möchtest, kannst du entweder darauf hoffen, dass sich jemand freiwillig den Stress macht dir alles zu erklären, oder du lernst es, indem du einfach darauf los scriptest und rumprobierst. Es macht keinen Sinn jemandem Scripten beizubringen, der nicht wenigstens eine grobe Vorstellung davon hat wie der Code überhaupt funktioniert, und wie man mittels der gegebenen elementaren Möglichkeiten (Variablen, if-Abfragen) an sein Ziel kommt. Probier dich durch die Funktionen durchzuarbeiten. Fang ganz einfach mit Funktionen, wie SendClientMessage an, verpack sie in if-Abfragen und benutze Variablen für verschiedene Bedingungen. Vllt willst du als nächstes fatbige Texte machen und steigst dahinter, wie Defines funktionieren. Dann kommen als nächstes Timer, und du lernst den Unterschied zwischen SetTimer ind SetTimerEx. Das bringt dich wiederum auf das Thema der einzelnen Parameter der Funktionen, die du benutzt. Dann fällt dir auch, dass du eine ganz spezielle Funktion mit ganz speziellen Parametern brauchst und entdeckst das Zauberwort "stock". Scripten zu Lernen ist quasi eine Kettenreaktion aus dem, was du bereits gelernt hast oder lernen willst und aus dem, wie du es benutzt und was dich interessiert. Mit der Zeit kommt dann das Verständnis und logische Denken. Schau dir ruhig mal diverse GameModes oder Filterscripts an (für den Anfang einfachere Sachen, hat es hier oder im englischen Forum zur Genüge) und lerne daraus. Kopieren wird dich nicht weit bringen, wenn du dir den Code dabei nicht genau anschaust. Das ganze braucht enorm viel Zeit (ich bin selber schon seit einem guten Jahr dabei aktiv scripten zu lernen). Ich habe es mir z.B. zul Ziel gesetzt, dass ich erst nach Funktionalität strebe, also, dass ein Code das tut, was er soll. Im Nachhinein mach ich mir Gedanken darüber, wie ich den Code kürzen kann, sodass er effizienter wird. Dann stoßt du auf Begriffe wie switch oder Unix Timestamp.


    Ich wünsch dir viel Erfolg! ;)