Skocz do zawartości
Strippin

Prosty system rejestracji/logowania

Rekomendowane odpowiedzi

1)Wprowadzenie i Przydatne Linki.

 

W tym systemie rejestracji oraz logowania, będziemy używać Y_INI oraz Whirlpool. Y_INI posłuży nam do zapisywania informacji o graczu, a Whirlpool będzie używany do "haszowania" (przerabiania tekstu na algorytm), haszowania użyjemy przy zapisywaniu hasła gracza. YSI oraz Whirlpool są autorstwa Y_less.

 

YSI: http://forum.sa-mp.com/showthread.php?p=1696956

Whirlpool: http://forum.sa-mp.com/showthread.php?t=65290

 

Intialisers(SA:MP Wiki): http://wiki.sa-mp.com/wiki/Keywords:Initialisers nas interesuje Enum i New(enumeratory)

Stock Functions(SA:MP Wiki): http://wiki.sa-mp.com/wiki/Stocks

Format(SA:MP Wiki): http://wiki.sa-mp.com/wiki/Format nas interesuje %s

Polskie SA:MP Wiki: http://wiki.sa-mp.com/wiki/Podstawy_i_zasady to co wyżej, lecz po polsku

 

Wszystkie funkcje postaram się jak najlepiej opisać, tworząc ten poradnik przyjazny osobom rozpoczynającym przygodę z PAWN.

 

2)Includy oraz Niezbędne Definicje..

 

Na samym początku dodamy Includy.

#include <a_samp>
#include <YSI\y_ini>

a_samp jest podstawową biblioteką SA:MP, y_ini będzie potrzebny aby zapisywać dane gracza na naszym serwerze w postaci plików .ini

Jako iż będziemy używać dialogów, musimy najpierw dodać definicje owych dialogów. Co prawda nie jest to wymagana gdyż możemy po prostu używać numerów dialogów, jednak definicje zaoszczędzą nam nerwów. Dialog są identyfikowane poprzez Id dialogów, są to zwykłe liczby. Definicje pozwalają na przypisywanie nazw do liczb, czyli zamiast pisać w funkcji numeru 123, wpiszemy np. DIALOG_1. Kiedy posiadamy skrypt/gamemode w którym jest sporo dialogów (przykładem mogą być gamemody Role Play), używanie liczb do identyfikacji może skończyć się kur*icą oraz błędami. Dodanie definicji jest proste jak bułka z masłem. Do naszego systemu użyjemy takich oto definicji:

#define DIALOG_REJESTRACJA          213 //liczba której byśmy normalnie użyli do identyfikacji dialogu 
#define DIALOG_LOGOWANIE             214 //liczba której byśmy normalnie użyli do identyfikacji dialogu 

Definicje mówią same za siebie, DIALOG_REJSTRACJA będzie używanie w dialogu z rejestracją, a DIALOG_LOGOWANIE przy dialogu logowania. Tutaj wchodzi plugin Whirlpool który opisałem wcześniej. Aby haszowanie działało poprawnie, musimy dodać jedną linijkę pod naszymi definicjami która będzie odpowiadała z komunikację z pluginem. Teraz dodamy definicję odpowiedzialną za miejsce przechowywania plików z danymi graczy.

#define UserPath "Konta/%s.ini"

Dzięki tej definicji, wszystkie pliki będą przechowywane w folderze Konta, który musimy dodać do folderu scriptfiles który jest używane do tego typu rzeczy. %s służy do przechowywania tekstu dla późniejszego użytku. W tym przypadku, %s będzie przechowywać nick gracza, po czym zostanie użyty do stworzenia pliku z jego danymi.

native WP_Hash(buffer[],len,const str[]);

Po dodaniu tej linijki jesteśmy gotowi rozpocząć następną część tego poradnika...

 

3)Ustawienia Systemu Zapisywania..

 

Aby nasz system działał, musimy dodać pewnie ustawienia. Zaczniemy od dodania "enumeratora", enumeratory są używane do zgrupowania większej ilości informacji, które potem można edytować. W naszym Enum zgrupujemy informacje o graczu, takie jak: ile razy gracz kogoś zabił, ile razy gracz został zabity, poziom VIP (opcjonalne, dla serwerów które posiadają opcje konto VIP), pieniędzy gracza, hasło gracza, jego Score (punkty z tabeli pod przyciskiem TAB) oraz dużo więcej. Pod tym co już mamy, dodajemy nasze Enum w taki sposób:

enum GraczInfo //rzeczy zaczynające się z g, np. gKasa można zmienić jak chcemy, ja użyłem dwóch angielskich słów, Kills i Deaths, użyłem ich gdyż znalazłem to z niewiadomych przyczyn wygodniejsze jako że mieszkam w Anglii.
{
    gPass[129], //hasło gracza, 129 oznacza maks znaków
    gVIP, //opcjonalne, będzie przechowywać poziom VIP'a gracza
    gKasa, 
    gScore,
    gKills, 
    gDeaths
}    

GraczInfo to grupa informacji, informacji o graczu. Jest ważne aby po ostatniej linijce nie dodawać przecinka, gdyż kompilator będzie oczekiwał kolejnej linijki co spowoduje błędy. Teraz dodamy nową zmienna której będziemy używać przy ładowaniu i zapisywaniu danych gracza.

 

Zmienna jest w zasadzie część pamięci, gdzie dane są przechowywane i mogą być zmienione i odczytywane zgodnie z wymaganiami. Zmienne zabierają jedną lub więcej komórek, komórki są 4 bajty duże i domyślnie podpisane więc mogą przechowywać numer od -2147483648 do 2147483647 (choć -2147483648 jest słabo zdefiniowane w PAWN i daje dziwne wyniki, jeśli wyświetlane). Zmienna wykonana z więcej niż jednej komórki nazywa się tablicą, ciąg to specjalny rodzaj tablicy, gdzie każda komórka posiada znak łańcucha (lub 4 znaki w pakowanym ciągu, ale nie są one opisane tutaj). - SA:MP Wiki Polska

new gInfo[MAX_PLAYERS][GraczInfo];

Kiedy już mamy naszą zmienną, dodam tzn. Stock. Stock jest używany do przechowywania wielu funkcji, zaoszczędzając nam czasu, oraz zasobów serwera. Więcej na ten temat jest w linku. A więc, nasz Stock będzie zawierał funkcje które ułatwią ładowanie i zapisywanie danych graczy, w wybranym przez nas miejscu.

stock Path(playerid) 
{
    new str[128],name[MAX_PLAYER_NAME]; //przechowuje nazwe gracza
    GetPlayerName(playerid,name,sizeof(name)); //funkcja pozyskiwania nazwy gracza
    format(str,sizeof(str),UserPath,name); //formatuje nazwę gracz do str
    return str;
}

Kiedy już to mamy, możemy zabrać się za pisanie kodu aby dane gracza były ładowane oraz zapisywane.

 

4)Ładowanie/Zapisywanie Danych Gracza i Rejstracja/Logowanie..

 

Zaczniemy od dodawania nowe funkcji publicznej, poprzez "forward". forward pozwala definiować funkcje publiczne które do późniejszego wykorzystania. My chcemy stworzyć nową publiczną funkcję do ładowania danych gracza z pliku. Robimy to w taki sposób:

forward wczytajkonto_user(playerid, name[], value[]);

Bez tej linijki, następny krok tej części poradniki byłby niemożliwy do wykonania, ważne jest aby znajdowała się ona nad naszą przyszłą publiczną funkcją, nie pod. Kiedy damy to pod naszą publiczną funkcje, kompilator będzie oczekiwał naszej funkcji pod naszym "forward", i będzie ignorował tą wyżej powodując błędy. Kiedy już mamy nasz "forward", pod nim dodajemy naszą publiczną funkcję:

public wczytajkonto_user(playerid, name[], value[])
{
    INI_String("Haslo",gInfo[playerid][gPass],129); //hasło gracza będzie załadowane
    INI_Int("VIP",gInfo[playerid][gVIP]);
    INI_Int("Kasa",gInfo[playerid][gKasa]); 
    INI_Int("Score",gInfo[playerid][gScore]);
    INI_Int("Kills",gInfo[playerid][gKills]);
    INI_Int("Deaths",gInfo[playerid][gDeaths]);
    return 1;
}

W naszej publicznej funkcji są same komendy dla systemu Y_INI. INI_String wczytuje tekst, w tym przypadku hasło gracza. INI_Int wczytuje liczbę, jak np. kasa, score czy ilość zabójstw. gInfo jest naszą zmienną, którą wcześniej dodaliśmy. gPass itp. to nasze dane które będą przechowywane, są one w naszym Stocku. Teraz przejdziemy do funkcji publicznej, OnPlayerConnect w której umieścimy kod który sprawdzi czy gracz jest zarejestrowany, jeśli nie to pokaże okno rejestracji, jeśli tak to pokaże okno logowania, jeśli gracz pomyślnie się zaloguje, pliki z jego danymi zostanie wczytany.

public OnPlayerConnect(playerid)
{
    new name[MAX_PLAYER_NAME]; //zmienna name będzie przechowywać nick gracza
    GetPlayerName(playerid,name,sizeof(name)); //sprawdza nick gracza, po czym dodaje go do zmiennej
    if(fexist(Path(playerid)))//sprawdza czy plik z danymi gracza istnieje (jest zarejestrowany)
    {
        INI_ParseFile(Path(playerid),"wczytajkonto_%s", .bExtra = true, .extra = playerid); //wczytuje plik z danymi gracza używając INI_ParseFile
        ShowPlayerDialog(playerid,DIALOG_LOGOWANIE,DIALOG_STYLE_INPUT,"Logowanie","Witamy, ten nick jest zarejestrowany. \nWpisz swoje hasło aby zalogować się do swojego konta.","Logowanie","Wyjdz"); //dialog logowania, w którym poda się hasło
    }
    else //jeśli nie jest zarejestrowany, zostanie zapytany o zarejestrowanie swojego konta
    {
        ShowPlayerDialog(playerid,DIALOG_REJESTRACJA,DIALOG_STYLE_INPUT,"Rejestracja","Witaj! to konto nie jest zarejestrowane.\nWpisz swoje hasło aby się zarejestrować.","Rejestruj","Wyjdź");
        return 1;
    }
    return 1;
}

Skoro mamy dialog, musimy mu przypisać funkcję. Przechodzimy do publicznej funkcji OnPlayerDialogResponse. Dodamy kod który sprawi że: Kiedy nowy gracz zarejestruj się, zostanie stworzony plik z wyzerowanymi danymi (oprócz hasła), jeśli się zaloguje, wczyta dane i je zastosuje dla gracza...

public OnDialogResponse(playerid, dialogid, response, listitem, inputtext[])
{
    if(dialogid == DIALOG_REJESTRACJA) //jeśli jest to dialog od rejestracji
    {
        if(!response) return Kick(playerid); //jeśli gracz kliknął Wyjdź, zostanie on wyrzucony z serwera
        if(response) //jeśli jednak kliknęli Rejestruj
        {
            if(!strlen(inputtext)) //jeśli nie podali hasła
            {//zmusimy ich do podania hasła
                ShowPlayerDialog(playerid,DIALOG_REJESTRACJA,DIALOG_STYLE_INPUT,"Rejestracja","Witaj! to konto nie jest zarejestrowane.\nWpisz swoje hasło aby się zarejestrować.","Rejestruj","Wyjdź");
                return 1;
            }
            //jeśli podali hasło
            new hashpass[129]; //nowa zmienna aby jego hasło zostało shaszowane
            WP_Hash(hashpass,sizeof(hashpass),inputtext);
            new INI:file = INI_Open(Path(playerid)); //utworzymy nowy plik na ich dane
            INI_SetTag(file,"Dane Gracza");//dodamy do pliku tag "Dane Gracza"
            INI_WriteString(file,"Haslo",hashpass);//zostanie dodane shaszowane hasło do konta gracza
            INI_WriteInt(file,"VIP",0);
            INI_WriteInt(file,"Kasa",0);      //
            INI_WriteInt(file,"Score",0);     //zeruje wszystkie dane
            INI_WriteInt(file,"Kills",0);      //
            INI_WriteInt(file,"Deaths",0);
            INI_Close(file);//po utworzeniu, i nadpisaniu pliku, zamykamy go
            SendClientMessage(playerid,-1,"Zostałeś pomyślnie zarejestrowany");
            return 1;
        }
    }
    if(dialogid == DIALOG_LOGOWANIE) 
    {
        if(!response) return Kick(playerid); //jeśli kliknęli Wyjdź, zostaną wyrzuceni
        if(response) //jeśli kliknęli Logowanie
        {//then
            new hashpass[129]; //zmienna taka sama jak wyżej
            WP_Hash(hashpass,sizeof(hashpass),inputtext); //tak samo jak wyżej
            if(!strcmp(hashpass, pInfo[playerid][Pass], false)) //jeśli podali prawidłowe hasło
            {//then
                INI_ParseFile(Path(playerid),"wczytajkonto_%s",.bExtra = true, .extra = playerid);//wczytamy dane z pliku
                //jeśli twój serwer posiada system VIP, tutaj funkcję która wczyta level VIP'a
                SetPlayerScore(playerid,gInfo[playerid][gScore]);//wczytaj, i ustawi score i money dla gracza
                GivePlayerMoney(playerid,gInfo[playerid][gKasa]);
                SendClientMessage(playerid,-1,"Witamy! zostałeś pomyślnie zalogowany.");
            }
            else //jeśli podali złe hasło
            {
                ShowPlayerDialog(playerid,DIALOG_LOGOWANIE,DIALOG_STYLE_INPUT,"Logowanie","Witamy, ten nick jest zarejestrowany. \nWpisz swoje hasło aby zalogować się do swojego konta.\n Nie poprawne hasło!","Logowanie","Wyjdz"); 
                return 1;
            }
        }
    }
    return 1;
}

Jak widzimy, jeśli podali złe hasło, zostanie ponownie wyświetlony dialog logowania. Teraz musimy dodać kod w publicznej funkcji OnPlayerDisconnect. Tutaj dodamy kod który zapisze dane gracza do pliku.

public OnPlayerDisconnect(playerid, reason)//wszystko już wcześniej opisałem 
{
        new INI:file = INI_Open(Path(playerid)); 
        INI_SetTag(file,"Dane Gracza");
        INI_WriteInt(file,"VIP",gInfo[playerid][gVIP]);
        INI_WriteInt(file,"Kasa",GetPlayerMoney(playerid));//wczyta stan kasy gracza, po czym to zapisze
        INI_WriteInt(file,"Score",GetPlayerScore(playerid));//tak jak wyżej
        INI_WriteInt(file,"Kills",gInfo[playerid][gKills]);
        INI_WriteInt(file,"Deaths",gInfo[playerid][gDeaths]);
        INI_Close(file);
    return 1;
}

Teraz, kiedy gracz będzie wychodził z serwera, jego dane zostaną zapisane. Teraz jeszcze tylko drobne szczegóły i system będzie gotowy!

 

 

5)Końcówka..

 

Skoro dodaliśmy możliwość przechowywania danych i ilości zabójstw i śmierci, musimy dodać kod który zmieni ich wartość przy zabiciu/śmierci. Kod jest bardzo prosty:

public OnPlayerDeath(playerid, killerid, reason)
{
    gInfo[killerid][gKills]++;//zostanie dodany jeden punkt do zabójstw
    gInfo[playerid][gDeaths]++;//zostanie dodany jeden punkt do śmierci
    return 1;
}

Teraz system jest już gotowy. Aby wszystko ładnie działało, musimy dodać w pliku konfiguracyjnym serwera plugin Whirlpool, tam gdzie pisze "plugins" dopisujemy Whirlpool

Gotowe ! masz swój własny system logowania/rejestracji wraz z zapisywaniem danych. Pamiętaj że zawsze można dodać więcej funkcji do przechowywania danych, dodajemy nowa linijkę w Stocku stosując się do innych, po czym dodaje funkcje ładowania i zapisywania w poszczególnych miejscach.

 

PS:Jeśli macie problemy, piszcie w komentarzach.

 

Poradnik: Prosty System Rejestracji/Logowania by Strippin - All rights reserved

Zakazuje kopiowania poradnika na inne fora niż pawno.pl

Edytowane przez Strippin

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Wybierz jeden język, w którym to piszesz skrypt. :)

Mi z jakiegoś powodu jest wygodniej używać angielskiego z polskim 50/50. Zawsze możecie zmienić gKills na co chcecie.

Edytowane przez Strippin

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

To taki bardziej gotowiec niż poradnik ale jest ok :)

Jeżeli ktoś będzie chciał, to dużo się z tego nauczy, bo nie każdemu trzeba tłumaczyć łopatologicznie - czyli tak, jak wymagasz.

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

@update

Nie zapomnijcie stworzyć folderu Konta, bo inaczej będziecie mieli problemy z uruchomieniem serwera. Folder dodajemy do Scriptfiles...

Edytowane przez Strippin

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Kopiuje wszystko do kodu tak jak w poradniku, pobrałem to co trzeba i wyskakują errory: 

 

Serwer.pwn(65) : error 017: undefined symbol "gInfo"
Serwer.pwn(68) : error 017: undefined symbol "gInfo"
Serwer.pwn(69) : error 017: undefined symbol "gInfo"
Serwer.pwn(88) : error 017: undefined symbol "gInfo"
Serwer.pwn(89) : error 017: undefined symbol "gInfo"
Serwer.pwn(276) : error 017: undefined symbol "pInfo"
Serwer.pwn(276) : warning 215: expression has no effect
Serwer.pwn(276) : error 001: expected token: ";", but found "]"
Serwer.pwn(276) : error 029: invalid expression, assumed zero
Serwer.pwn(276) : fatal error 107: too many error messages on one line

 
Posiedziałem nad tym troche i zrobiłem.
 
 
PS. Tutaj gdzie mamy linijke
 
if(!strcmp(hashpass, pInfo[playerid][Pass], false)) //jeśli podali prawidłowe hasło
 
musimy zmienić tam gdzie mamy Pass na gPass, tak jak to podane jest w enum :)

 
Edytowane przez Tigers

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Błagam wytłumaczcie mi dlaczego tablica nazywa się "GraczInfo" a jej pola to "score", "kasa", "kills" ......

Zdecydujcie się w jakim języki piszecie!

 

No racja ale ja uważam, że jeśli by to pisał dla siebie to niech sobie nazywa jak chce. Ale jak to ma być już ogólnodostępny poradnik to niech to ma ręce i nogi!

Edytowane przez dawid4157

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

A ja się z tym nie zgadzam. Jakikolwiek kod powinien być pisany wedle standardów i konwencji.

Nagle coś się zepsuje, gość z takim gówno-kodem idzie na forum i reszta programistów musi to czytać.

Albo jeszcze lepiej, gość sprzeda taki kod i jakiś biedny programista będzie musiał z tym pracować na co dzień.

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

ajajaj zawsze byłem przy dini ale czas to zmienić i są errory :/
 

pawno\include\YSI\y_ini.inc(418) : error 017: undefined symbol "strcpy"
pawno\include\YSI\y_ini.inc(465) : error 017: undefined symbol "strcpy"
pawno\include\YSI\y_ini.inc(590) : error 017: undefined symbol "strcpy"
pawno\include\YSI\y_ini.inc(712) : error 017: undefined symbol "strcpy"
pawno\include\YSI\y_ini.inc(712) : warning 202: number of arguments does not match definition
pawno\include\YSI\y_ini.inc(984) : error 017: undefined symbol "strcpy"
pawno\include\YSI\y_ini.inc(1009) : error 017: undefined symbol "strcpy"
pawno\include\YSI\y_ini.inc(1011) : error 017: undefined symbol "strcpy"
Militaria.pwn(11) : error 017: undefined symbol "PlayerInfo"
Militaria.pwn(11) : error 009: invalid array size (negative, zero or out of bounds)
Militaria.pwn(72) : warning 213: tag mismatch
Militaria.pwn(73) : warning 213: tag mismatch
Militaria.pwn(75) : warning 217: loose indentation
Militaria.pwn(94) : error 021: symbol already defined: "S@@_OnPlayerDeath"
Militaria.pwn(95) : warning 213: tag mismatch
Militaria.pwn(96) : warning 213: tag mismatch
Militaria.pwn(249) : error 017: undefined symbol "WP_Hash"
Militaria.pwn(249) : warning 202: number of arguments does not match definition

 

Kod

 

http://pastebin.com/2UbfRsxY



Edit: Mógłby ktoś podesłać swoją bibliotekę YSI? Bo ściągam YSI 4 i coś się gryzie :/

Edytowane przez Stp90PL

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

  • Przeglądający   0 użytkowników

    Brak zarejestrowanych użytkowników przeglądających tę stronę.

×