Skocz do zawartości

Witamy w Nieoficjalnym polskim support'cie AMX Mod X

Witamy w Nieoficjalnym polskim support'cie AMX Mod X, jak w większości społeczności internetowych musisz się zarejestrować aby móc odpowiadać lub zakładać nowe tematy, ale nie bój się to jest prosty proces w którym wymagamy minimalnych informacji.
  • Rozpoczynaj nowe tematy i odpowiedaj na inne
  • Zapisz się do tematów i for, aby otrzymywać automatyczne uaktualnienia
  • Dodawaj wydarzenia do kalendarza społecznościowego
  • Stwórz swój własny profil i zdobywaj nowych znajomych
  • Zdobywaj nowe doświadczenia

Dołączona grafika Dołączona grafika

Guest Message by DevFuse
 

Zdjęcie

Dobre i złe nawyki tworzenia menu


  • Nie możesz napisać tematu
  • Zaloguj się, aby dodać odpowiedź
38 odpowiedzi w tym temacie

#1 GwynBleidD

    Godlike

  • Przyjaciel

Reputacja: 1 869
Godlike

  • Postów:3 066
  • Steam:steam
  • Lokalizacja:Przemyśl
Offline

Napisano 14.05.2012 14:00

*
Popularny

Krótka przedmowa, czyli o czym ten poradnik

Będzie to poradnik nie o samym tworzeniu menu, lecz o tym jak to, w zależności od sytuacji, robić prawidłowo. Skupię się tutaj wyłącznie na nowym typie menu, który w najnowszym amx umożliwia prawie tą samą funkcjonalność, co stary typ menu, a dużo większą wygodę użycia. Jedynym brakiem tutaj jest brak możliwości utworzenia linii informacyjnej przed pierwszym elementem w menu (czyli zaraz pod tytułem), co jednak można obejść tworząc wielolinijkowy tytuł, o czym na końcu tego tutorialu w ramach bonusu :) W praktyce będzie to prawie wyłącznie o użyciu info w menu, czyli jak go używać z głową i do czego może się przydać.

Omówienie funkcji zostawiam dokumentacji :) Najpierw omówię złe praktyki i opiszę dlaczego są złe


1. Konstruowanie switcha w oparciu o info

Często widzę taki "koszmarek" jak sterowanie switchem w handlerze poprzez info, gdzie w info zawiera się numer pozycji, w postaci tekstu. Jeśli nie wiesz o czym mówię, zobacz przykład:



public show_menu(id) {
    new menu = menu_create("Menu serwera", "handle_menu");
    
    menu_additem(menu, "Wyświetl regulamin", "1");
    if(cs_get_user_team(id)==CS_TEAM_CT)
        menu_additem(menu, "Kup AK47", "2");
    else
        menu_additem(menu, "Kup M4A1", "2");
    menu_additem(menu, "Wyświetl top15", "3");
    menu_additem(menu, "Zobacz inne serwery", "4");
    menu_additem(menu, "Przekaż pieniąde graczowi", "5");
    
    menu_display(id, menu)
}

public handle_menu(id, menu, item) {
    if(item == MENU_EXIT) {
        menu_destroy(menu);
        return PLUGIN_HANDLED;
    }

    new sKey[6], iKey, access, callback;
    menu_item_getinfo(menu, item, access, sKey, 5,_, _, callback);
    iKey = str_to_num(sKey);
    
    switch(iKey) {
        case 1: client_cmd(id, "say /regulamin");
        case 2: daj_bron(id);
        case 3: client_cmd(id, "say /top15");
        case 4: client_cmd(id, "say /serwery");
        case 5: client_cmd(id, "say /przelew");
    }
    
    menu_destroy(menu);
    return PLUGIN_HANDLED;
}

Co tu i dlaczego jest źle? a to, że wymyślamy koło na nowo i marnotrawimy zasoby. Otóż niepotrzebnie używamy 3ciego parametru itemów z menu o nazwie info, aby determinować co klient kliknął w menu, przez co generujemy niepotrzebne utworzenie 3ch zmiennych w handlerze, konieczność pobrania info i przekonwertowania na postać numeryczną + podanie do każdego itemu dodatkowego parametru info, co generuje dodatkowe zużycie zasobów. Może i niewielkie, ale na pewno niepotrzebne :) Więc na pewno tworzenie menu w taki sposób dobrą praktyką nie jest.


ad 1. Konstruowanie switcha w oparciu o parametr item

Teraz poprawna wersja z użyciem, stworzonego do tego celu, parametru item z handlera, który przechowuje numer tego elementu, licząc od 0, czyli ten sam plugin wyglądać może tak:

public show_menu(id) {
    new menu = menu_create("Menu serwera", "handle_menu");
    
    menu_additem(menu, "Wyświetl regulamin");
    if(cs_get_user_team(id)==CS_TEAM_CT)
        menu_additem(menu, "Kup AK47");
    else
        menu_additem(menu, "Kup M4A1");
    menu_additem(menu, "Wyświetl top15");
    menu_additem(menu, "Zobacz inne serwery");
    menu_additem(menu, "Przekaż pieniąde graczowi");
    
    menu_display(id, menu)
}

public handle_menu(id, menu, item) {
    if(item == MENU_EXIT) {
        menu_destroy(menu);
        return PLUGIN_HANDLED;
    }

    switch(item) {
        case 0: client_cmd(id, "say /regulamin");
        case 1: daj_bron(id);
        case 2: client_cmd(id, "say /top15");
        case 3: client_cmd(id, "say /serwery");
        case 4: client_cmd(id, "say /przelew");
    }

    menu_destroy(menu);
    return PLUGIN_HANDLED;
}

i gwarantuję, że zadziała tak samo, a nawet lepiej ;) Numeracja w item jest niezależna od numeracji klawiszy w menu, więc każdy additem i tylko additem zwiększa nam numer o 1, zaczynamy od 0 o czym trzeba pamiętać koniecznie. Exit nie ma numeru 0, ale specjalną wartość nazwaną MENU_EXIT, równą -3 (-2 i -1 to odpowiednio wstecz i dalej).


Trochę o samym parametrze info

No dobra, ale czym w końcu jest to info? Ano jest to informacja, którą możemy przekazać do handlerów menu, aby poinformować go o tym, co zawiera dana opcja. W przypadku przykładu 1, gdzie tworzymy je w kodzie statycznie lub prawie statycznie (różni się etykieta itemu pod klawiszem 2 w zależności od drużyny w podanym przykładzie) jest całkowicie zbędne. Jednak może się przydać przy tworzeniu dynamicznego menu. Oto następna zła praktyka:


2. Nieprawidłowe menu z graczami

Przyjrzyjmy się przykładowej implementacji menu do przelewu kasy, w którym możemy wybrać danego gracza i przelać mu pieniądze. Dla uproszczenia przyjąłem, że podaną funkcję show_przelew wywołuje handler z poprzedniego menu wyboru ilości kasy do przelania. Ilość ta jest podana w parametrze wartosc. gWartosci to 33 elementowa tablica globalna:

public show_przelew(id, wartosc) {
    new menu = menu_create("Wybierz gracza do przelania kasy", "handle_przelew");
    
    gWartosci[id] = wartosc;
    
    new players[32], num;
    get_players(players, num);
    for(new i=0; i<num; ++i) {
        new name[32];
        get_user_name(players[i], name, 31);
        menu_additem(menu, name);
    }
    
    menu_display(id, menu);
}

public handle_przelew(id, menu, item) {
    if(item == MENU_EXIT) {
        menu_destroy(menu);
        return PLUGIN_HANDLED;
    }

    new players[32], num;
    get_players(players, num);
    przelej_kase(id, players[item], gWartosci[id]);
    
    menu_destroy(menu);
    return PLUGIN_HANDLED;
}

Niby wszystko pięknie, na oko i po pierwszych testach działa, bo przecież itemów tworzymy tyle ile graczy, więc item będzie nam zwracał zawsze pozycję w tablicy players, którą zajmował dany gracz. No prawie... Bo co się stanie jak ktoś wyjdzie z serwera albo ktoś na serwer wejdzie? Jeśli nastąpi to w tablicy po indeksie gracza, którego chcemy wybrać to jeszcze pół biedy, ale jeśli przed to kolejność się zmieni. A niestety widziałem takie praktyki w wielu pluginach... No i w tym momencie dajemy kasę nie temu graczowi co trzeba...


ad 2. Prawidłowo działające menu z graczami

Jak to poprawić? użyć info! Tutaj, w przeciwieństwie do przykładu pierwszego, należy go użyć. Więc używajmy:

public show_przelew(id, wartosc) {
    new menu = menu_create("Wybierz gracza do przelania kasy", "handle_przelew");
    
    new players[32], num;
    new name[32], info[25];
    get_players(players, num);
    for(new i=0; i<num; ++i) {
        get_user_name(players[i], name, 31);
        formatex(info, 24, "%08X%08X%08X", wartosc, players[i], get_user_userid(players[i]));
        /*info[0] = wartosc; POPRAWKA - TEGO SPOSOBU WIĘCEJ NIE UŻYWAMY!
        info[1] = players[i];
        info[2] = get_user_userid(players[i]); */
        menu_additem(menu, name, info);
    }
    
    menu_display(id, menu);
}

public handle_przelew(id, menu, item) {
    if(item == MENU_EXIT) {
        menu_destroy(menu);
        return PLUGIN_HANDLED;
    }
    
    new info[25], access, callback;
    menu_item_getinfo(menu, item, access, info, 24,_, _, callback);
    new tid = hexstr_to_num(info[8], 8); // zaczynamy od 8 znaku i pobieramy 8 z nich, konwertując je z hex na liczbę
    new tuserid = hexstr_to_num(info[16], 8);
    new wartosc = hexstr_to_num(info, 8);
    if(is_user_connected(tid) && tuserid == get_user_userid(tid))
        przelej_kase(id, tid, wartosc);

    menu_destroy(menu);
    return PLUGIN_HANDLED;
}
hexstr_to_num(string[], chars) {
    new result=0;
    for(new i=0; i<chars && string[i]!='^0'; ++i)
        result = result<<4 + (string[i]>'9'?string[i]>'F'?string[i]-'a'+10:string[i]-'A'+10:string[i]-'0');
        return result;
    }
}

Jak widać potrzebne wartości, czyli id gracza i wartość kasy do przelania. Ale co? Przecież to nie jest napis, tylko tablica... A kto powiedział albo gdzieś napisał, że info musi być napisem? Może być tablicą, wszak napis też jest tablicą, tyle że specyficznie interpretowaną ;) więc zastosowanie jak najbardziej prawidłowe. (Znów aktualizacja! Ostatnio odkryłem, że niestety gdy funkcja napotka wartość 0, przerywa całkowicie wczytywanie dalszych wartości! Musimy więc przerobić liczbę na string!) Utworzyłem prosty string z 3 wartości liczbowych w postaci heksadecymalnej. Użyłem dość dziwnej konstrukcji %08F, zapewnia to wypełnienie zerami z przodu tak, aby liczba zawsze zajmowała 8 znaków. Dlaczego każda ma 8? liczba każda w AMX ma 32 bity, jedna cyfra HEX może zapisać 4, dalej chyba już jasne :) Stworzyłem również funkcję konwertującą string hexadecymalny na liczbę, aby wydobyć ze stringa spowrotem wartości. Dlaczego użyłem HEX? Prościej jest konwertować to na liczbę i zajmuje stałą ilość znaków ;) Teraz już nie martwimy się, że jakiś gracz ucieknie z serwera (no chyba, że ucieka nam gracz, do którego chcemy przelać kasę... ale wtedy po prostu kasa się nie przeleje, chyba że ktoś na miejsce wychodzącego gracza akurat wejdzie, na taki przypadek można zrobić weryfikację nicku lub sid jeszcze) (aktualizowałem kod pluginu zgodnie z sugestią użytkownika sebul) i mamy elegancko zrobione menu :) Jednocześnie zbędna stała się globalna tablica gWartosci, gdyż wartość kasy przesyłamy w tym samym info, co id gracza.
Mam nadzieję, że przykład ten jasno ilustruje do czego info w nowych menu powinno być używane.


3. Menu statyczne wyboru serwera, przykład nieco gorszy

Teraz jeszcze jeden przykład uzasadnionego użycia info, mimo menu statycznego. Oczywiście na początek ten... może tym razem po prostu gorszy, bo jak najbardziej poprawny ;) przykład, menu serwerów:

public show_serwery(id) {
    new menu = menu_create("Wybierz serwer na który chcesz przejść", "handle_serwery");
    
    menu_additem(menu, "Serwer GunGame");
    menu_additem(menu, "Serwer FFA");
    menu_additem(menu, "Serwer Diablo");
    
    menu_display(id, menu);
}

public handle_serwery(id, menu, item) {
    if(item == MENU_EXIT) {
        menu_destroy(menu);
        return PLUGIN_HANDLED;
    }

    switch(item) {
        case 0: client_cmd(id, "Connect 23.123.33.22:27033");
        case 1: client_cmd(id, "Connect 12.34.56.78:27090");
        case 2: client_cmd(id, "Connect 98.76.54.32:27010");
    }

    menu_destroy(menu);
    return PLUGIN_HANDLED;
}

Dlaczego przykład jest gorszy? trudniejszy w edycji, musimy w 2ch miejscach zmieniać, gdy chcemy zmienić listę serwerów.


ad 3. Menu wyboru serwera, przykład lepszy, wygodniejszy

Mimo, że poprawny jest, przedstawiam wariant wygodniejszy:

public show_serwery(id) {
    new menu = menu_create("Wybierz serwer na który chcesz przejść", "handle_serwery");
    
    menu_additem(menu, "Serwer GunGame", "23.123.33.22:27033");
    menu_additem(menu, "Serwer FFA", "12.34.56.78:27090");
    menu_additem(menu, "Serwer Diablo", "98.76.54.32:27010");
    
    menu_display(id, menu);
}

public handle_serwery(id, menu, item) {
    if(item == MENU_EXIT) {
        menu_destroy(menu);
        return PLUGIN_HANDLED;
    }

    new ip[32], access, callback;
    menu_item_getinfo(menu, item, access, ip, 31,_, _, callback);
    client_cmd(id, "Connect %s", ip);
    
    menu_destroy(menu);
    return PLUGIN_HANDLED;
}

W ten oto sposób mamy dużo wygodniejsze dodawanie i edycję listy serwerów, bo dla każdego serwera jest to jedna, przejrzysta linia. Dodatkowo drobną modyfikacją można uzyskać listę serwerów odczytywaną z pliku, nvaulta albo bazy SQL, wstawiając odpowiednią pętlę zamiast additem, oraz dodając obsługę jednego z wymienionych. Tutaj, mimo menu statycznego, mamy w pełni uzasadnione użycie info do determinowania akcji podejmowanej przez menu :)


I na koniec obiecany bonus

Jak wiecie, dzięki starym menu można tworzyć coś, co przypomina, albo i nie przypomina menu, np wyświetlić regulamin na kilkanaście linii i pod nim dać możliwość jego akceptacji. Na nowym menu można dokładnie to samo, wymaga to jednak tricków kilku.

O ile nie ma żadnych problemów, gdy np. chcemy wstawić po każdej opcji w menu linijkę opisującą, albo gdy wszystkie opcje w menu mają być na samej górze, a dodatkowy tekst na dole, gdyż jest coś takiego jak menu_addblank i menu_addtext. Nie możemy ich jednak użyć przed użyciem choć raz menu_additem (nie wiem dlaczego tak twórcy amx głupio zrobili, ale tak zrobili). Jednak jest możliwość ominięcia tego niuansu przez ustawienie potrzebnych nam rzeczy w wielolinijkowym tytule. Tu następne ograniczenie: ustawienie tytułu poprzez menu_create posiada dosyć rygorystyczny limit znaków, musimy więc ustawić to poprzez menu_setprop(menu, MPROP_TITLE, ...) czyli np coś takiego:

    menu = menu_create("Regulamin serwera", "handler");
    menu_setprop(menu, MPROP_TITLE, "Regulamin serwera \yGunGame^n^nNa serwerze obowiązuje\rABSOLUTNY\yzakaz przeklinania^nNie wolno bugować mapy...");

    menu_additem(menu, "Akceptuję regulamin");
    menu_additem(menu, "Nie akceptuję regulaminu");
    menu_addtext(menu, " Nie zaakceptowanie regulaminu wiąże się z 5 minutowym banem");
    menu_setprop(menu, MPROP_EXIT, MEXIT_NEVER);

I w taki sposób uzyskujemy ładny, czytelny regulamin, na nowych menu, z możliwością akceptacji ;) Prawda, że proste :)

Dziękuję za dotrwanie do końca :D

Copyright © Wszelkie prawa zastrzeżone
Kopiowanie tego poradnika lub treści w nim zawartych bez wyraźnej zgody autora jest zabronione i będzie ścigane z mocy prawa


Użytkownik GwynBleidD edytował ten post 16.05.2013 18:29

  • +
  • -
  • 20

NIE pomagam na PW. Nie trudź się, na zlecenia nie odpiszę... Od pomagania jest forum.
NIE zaglądam w tematy wysłane na PW. Jeśli są na forum to prędzej czy później je przeczytam. Jeśli mam co w nich odpisać, to odpiszę.
 
1988650.png?theme=dark


#2 ogieR8

    Wszechmogący

  • Power User

Reputacja: 203
Profesjonalista

  • Postów:641
  • Imię:Mariusz
  • Lokalizacja:Ruda Śląska
Offline

Napisano 14.05.2012 15:43

Przeczytałem, przyznam że nawyk pierwszy miałem i myślałem, że służy to właśnie numeracji ;PP Łap +'a, nowych rzeczy się dowiedziałem, jednak tego stylu używam tylko jeśli robię bardzo objętościowe menu, np na kupienie wybranego itemy, gdy mamy ich do wybrania załóżmy 150, ale tak ogólnie to wolę z nawyku korzystać ze starego, dla mnie jest łatwiejszy ^^

Użytkownik ogieR- edytował ten post 14.05.2012 15:43

  • +
  • -
  • 1

Irytuje mnie nieczytelny kod, jeśli oczekujesz ode mnie pomocy - zmień to !


#3 sebul

    Godlike

  • Przyjaciel

Reputacja: 2 035
Godlike

  • Postów:5 411
  • Steam:steam
  • Imię:Sebastian
  • Lokalizacja:Ostrołęka
Offline

Napisano 14.05.2012 17:54

Raczej błędów nie ma, ale

no chyba, że ucieka nam gracz, do którego chcemy przelać kasę... ale wtedy po prostu kasa się nie przeleje, chyba że ktoś na miejsce wychodzącego gracza akurat wejdzie, na taki przypadek można zrobić weryfikację nicku lub sid jeszcze

lepiej po prostu zapisywać do jakiejś globalnej tablicy 33-elementowej id gracza, chodzi o te id, co wyciąga się je funkcją get_user_userid, a potem sprawdzać te id po wybraniu gracza z menu.
  • +
  • -
  • 1

Posiadam TBM (inaczej PTB), które działa dużo lepiej niż zwykłe PTB, nawet na modach z lvlami. Zainteresowany? Proszę bardzo


#4 GwynBleidD

    Godlike

  • Autor tematu
  • Przyjaciel

Reputacja: 1 869
Godlike

  • Postów:3 066
  • Steam:steam
  • Lokalizacja:Przemyśl
Offline

Napisano 14.05.2012 20:25

Raczej błędów nie ma, ale

no chyba, że ucieka nam gracz, do którego chcemy przelać kasę... ale wtedy po prostu kasa się nie przeleje, chyba że ktoś na miejsce wychodzącego gracza akurat wejdzie, na taki przypadek można zrobić weryfikację nicku lub sid jeszcze

lepiej po prostu zapisywać do jakiejś globalnej tablicy 33-elementowej id gracza, chodzi o te id, co wyciąga się je funkcją get_user_userid, a potem sprawdzać te id po wybraniu gracza z menu.


//edytowane
Nie trzeba tego robić w globalnej tablicy, można rozszerzyć info o dodatkowe pole, w którym będzie się to ID przekazywać ;) Bo tworzenie globalnej tablicy 2 wymiarowej o wymiarach 33x33 tylko dla takiego zastosowania mija się z celem... (każdy gracz może wywołać to menu niezależnie i z różnym opóźnieniem wybrać z niego opcję, więc nie może być jedna 33 elementowa tablica). Dobrze jest unikać tablic globalnych w miejscach, gdzie przekazać możemy dane do następnej funkcji przez taką strukturę, np w set_task lub SQL_ThreadQuery.

Swoją drogą znalazłem błąd w swoim własnym poradniku. W żadnym miejscu nie używam menu_destroy, przez co jest wyciek pamięci (menu jest tworzone dla każdego wywołania nowe, więc trzeba je usuwać). Poprawiłbym ale nie mam możliwości edycji postu już... Można prosić jakiegoś moda o dodanie tego przed każdym return... ? Oczywiście klamry dodać w miejscach, gdzie są potrzebne ;) Drugim błędem jest próba użycia [amxx] w "bonusie", nie pamiętałem jaki był bbcode na link do dokumentacji, chciałem przetestować, ale jakoś tak zostało... Mógłby też ktoś dodać to, co napisałem wyżej w poście odnośnie weryfikacji gracza, albo po prostu dać mi możliwość edycji :D

Użytkownik GwynBleidD edytował ten post 14.05.2012 20:31

  • +
  • -
  • 0

NIE pomagam na PW. Nie trudź się, na zlecenia nie odpiszę... Od pomagania jest forum.
NIE zaglądam w tematy wysłane na PW. Jeśli są na forum to prędzej czy później je przeczytam. Jeśli mam co w nich odpisać, to odpiszę.
 
1988650.png?theme=dark


#5 sebul

    Godlike

  • Przyjaciel

Reputacja: 2 035
Godlike

  • Postów:5 411
  • Steam:steam
  • Imię:Sebastian
  • Lokalizacja:Ostrołęka
Offline

Napisano 14.05.2012 20:49

Przepraszam, nie doczytałem wcześniej, że chodzi o id z get_user_userid, edytowałem poprzedni post, teraz zawiera "właściwą" odpowiedź na Twojego posta, więc ten i Twój post można wywalić :D

Nie można, bo mam jeszcze inną uwagę ;]

Nie trzeba tego robić w globalnej tablicy, można rozszerzyć info o dodatkowe pole, w którym będzie się to ID przekazywać ;) Bo tworzenie globalnej tablicy 2 wymiarowej o wymiarach 33x33 tylko dla takiego zastosowania mija się z celem... (każdy gracz może wywołać to menu niezależnie i z różnym opóźnieniem wybrać z niego opcję, więc nie może być jedna 33 elementowa tablica). Dobrze jest unikać tablic globalnych w miejscach, gdzie przekazać możemy dane do następnej funkcji przez taką strukturę, np w set_task lub SQL_ThreadQuery.

W sumie robić może i nie trzeba, ale co do tworzenia tej zmiennej źle mnie zrozumiałeś. Wystarczy 33-elementowa tablica, a nie 33x33, wystarczy coś takiego:
przy wywołaniu/tworzeniu menu
zmienna[players[i]] = get_user_userid(players[i]);

a następnie po wybraniu już gracza warunek
if(zmienna[info[1]] == get_user_userid(info[1]))

na podstawie "ad 2. Prawidłowo działające menu z graczami". Oczywiście można zrobić tak jak napisałeś, ale czasami może się okazać, że przez menu chcemy przekazać coś innego, np. jakiś ciąg znaków.
  • +
  • -
  • 0

Posiadam TBM (inaczej PTB), które działa dużo lepiej niż zwykłe PTB, nawet na modach z lvlami. Zainteresowany? Proszę bardzo


#6 G[o]Q

    I'm G[o]Q

  • Przyjaciel

Reputacja: 1 344
Godlike

  • Postów:3 563
  • Steam:steam
  • Imię:Krzysiek
  • Lokalizacja:C: / program Files / Valve / Cstrike / G[o]Q.dem
Offline

Napisano 14.05.2012 20:54

sebul po to jest wlasnie ten parametr ktorego "znaczenia nikt nie zna " tam wrzucasz id goscia albo userid do stringa tu juz sobie wybierasz ewentualnie zeby miec 100% pewnosci moze być nick chociaz najlepiej wlasnie userid i potem bierzesz
menu_item_getinfo
i na podstawie tego stringa szukasz osoby to jedyne zastosowanie
menu_item_getinfo
które ma sens

nie musze dodawać ze wg mnie temat bez sensu bo kazdy sam sobie wyrabia nawyki i będzie robić tak jak będzie mu wygodniej/łatwiej/ladnie to tak ja z klamerkami czy dawać je w nowych liniach czy nie xD
  • +
  • -
  • 0
Manual ponad wszystko, konsola ponad manual :D :&

Chcesz wysłać do mnie PW ? użyj nazwy GoQ zamiast G[o]Q
Chcesz Kupić moduł płatności via Pukawka,Tserwery, Gamesol, Zabijaka do mojego sklepu? napisz PW cena to tylko 10 zł/sztuka

GG:6022845 (nie pomagam za free osobom ponizej rangi MoD) :D

#7 sebul

    Godlike

  • Przyjaciel

Reputacja: 2 035
Godlike

  • Postów:5 411
  • Steam:steam
  • Imię:Sebastian
  • Lokalizacja:Ostrołęka
Offline

Napisano 14.05.2012 21:06

sebul po to jest wlasnie ten parametr ktorego "znaczenia nikt nie zna " tam wrzucasz id goscia albo userid do stringa

Tak, ale co jeśli chcesz przekazać jakiś ciąg znaków w tym parametrze? Bo o taki przypadek mi właśnie chodziło, nie zawsze łatwiej/lepiej jest wszystko pchać do jednego parametru, a już nie wspomnę gdy mamy jakieś rozbudowane menu, które ma różne "pod menu", wtedy najłatwiej jest używać zmiennych globalnych.
  • +
  • -
  • 0

Posiadam TBM (inaczej PTB), które działa dużo lepiej niż zwykłe PTB, nawet na modach z lvlami. Zainteresowany? Proszę bardzo


#8 GwynBleidD

    Godlike

  • Autor tematu
  • Przyjaciel

Reputacja: 1 869
Godlike

  • Postów:3 066
  • Steam:steam
  • Lokalizacja:Przemyśl
Offline

Napisano 14.05.2012 21:11

@sebul Już Ci prezentuję dlaczego nie można tego zrobić na 1 wymiarowej tablicy ;) Przeanalizujmy sytuację: 3 graczy na serwerze, jeden z graczy wchodzi w menu i przez dłuższy czas nic nie wybiera, następnie drugi gracz wychodzi z serwera a na jego miejsce wchodzi inny, dostając ID po poprzednim, gracz 3ci (będący na serwerze już wcześniej) wchodzi w tym momencie w menu (aktualizuje się zaproponowana przez Ciebie tablica) i w tym momencie gracz 1szy decyduje, że przeleje kasę temu graczowi, który wyszedł. Efekt? zabezpieczenie nie zadziałało.

Jeśli chcesz w info w menu przekazać czasem jakąś inną informację, można zawsze tablicę powiększyć, a nawet pogodzić w niej kilka stringów i danych liczbowych w następujący sposób:
new tablica[64]
copy(nick, tabilca, 31);
copy(sid, tablica[32], 30);
tablica[63] = id;

i w ten sposób przekazać można poprzez info do innej funkcji cały pakiet informacji o graczu ;)

@G[o]Q, poradnik ma sens i różni się trochę od tego, jak stawiać klamry (a z klamrami się zgodzę, nikt mnie nie przekona, że czytelniej jest otwierać klamry w nowej linii) ponieważ wiele osób (patrz 1 odpowiedź, tak na dowód) nie wie, że info w menu można wykorzystać do tego lub jest przekonana, że to info jest klawiszem w menu (w starym additem było nazwane key, co wprowadzało w błąd, a zastosowanie było to samo).
  • +
  • -
  • 0

NIE pomagam na PW. Nie trudź się, na zlecenia nie odpiszę... Od pomagania jest forum.
NIE zaglądam w tematy wysłane na PW. Jeśli są na forum to prędzej czy później je przeczytam. Jeśli mam co w nich odpisać, to odpiszę.
 
1988650.png?theme=dark


#9 Jak się nazwać

    Wszechmogący

  • Power User

Reputacja: 169
Profesjonalista

  • Postów:617
  • Imię:a
  • Lokalizacja:a
Offline

Napisano 14.05.2012 21:16


new sKey[6], iKey, access;
menu_item_getinfo(menu, item, access, sKey, 5);
iKey = str_to_num(sKey);

switch(sKey) {

jak dla mnie zmienna iKey jest nieużywana
  • +
  • -
  • 0
Pisze na zamówienie statystyki pod nvault. GG: 15600964

#10 G[o]Q

    I'm G[o]Q

  • Przyjaciel

Reputacja: 1 344
Godlike

  • Postów:3 563
  • Steam:steam
  • Imię:Krzysiek
  • Lokalizacja:C: / program Files / Valve / Cstrike / G[o]Q.dem
Offline

Napisano 14.05.2012 21:17

wydaje mi sie ze sebul pisal o menu wspólnym dla wszystkich graczy np vote i wtedy mial racje a nawet w wypadku ktory ty opisales to on nadal ma akcje bo poprostu jesli userid nie bd sie zgadzać to dzialanie się nie wykona i dlatego moje rozwiązanie jest najlepsze a po to zeby przekazywać tez inne parametry są funkcje replace_all i parse :D
  • +
  • -
  • 0
Manual ponad wszystko, konsola ponad manual :D :&

Chcesz wysłać do mnie PW ? użyj nazwy GoQ zamiast G[o]Q
Chcesz Kupić moduł płatności via Pukawka,Tserwery, Gamesol, Zabijaka do mojego sklepu? napisz PW cena to tylko 10 zł/sztuka

GG:6022845 (nie pomagam za free osobom ponizej rangi MoD) :D

#11 GwynBleidD

    Godlike

  • Autor tematu
  • Przyjaciel

Reputacja: 1 869
Godlike

  • Postów:3 066
  • Steam:steam
  • Lokalizacja:Przemyśl
Offline

Napisano 14.05.2012 21:29


new sKey[6], iKey, access;
menu_item_getinfo(menu, item, access, sKey, 5);
iKey = str_to_num(sKey);

switch(sKey) {

jak dla mnie zmienna iKey jest nieużywana


Racja, powinno być
switch(iKey) {

prosiłbym kogoś z moderacji o poprawę, gdyż sam tego zrobić nie mogę ;)

@G[o]Q, w tym sęk, że w opisywanym przeze mnie przypadku korzystania z tablicy globalnej userid będzie się zgadzać, bo w globalnej tablicy będzie on aktualizowany przy każdym wywołaniu menu przez kogokolwiek, a w handlerze będzie na bieżąco pobierany. Nie wierzysz? Zasymuluj to sobie choćby na kartce (rozpisz zmienne i wywołuj odpowiednie funkcje), albo nawet w prostym programie w c++: tworzysz globalną tablicę 3 elementową, wypełniasz 3ma liczbami różnymi, tworzysz funkcję, która przekopiuje tą tablicę do drugiej tablicy globalnej oraz funkcję, która porówna wybrany element z jednej i drugiej. Następnie w main wywołujesz: 1 funkcję (wywołanie menu przez 1 gracza), zamieniasz środkową wartość w pierwotnej tablicy (podmiana 2 gracza), 1 funkcję (wywołanie menu przez 3 gracza), porównujesz środkową wartość w tablicach. Efekt łatwy do przewidzenia, a jest to wierna symulacja przypadku w tym rozwiązaniu.

Użytkownik GwynBleidD edytował ten post 14.05.2012 21:30

  • +
  • -
  • 0

NIE pomagam na PW. Nie trudź się, na zlecenia nie odpiszę... Od pomagania jest forum.
NIE zaglądam w tematy wysłane na PW. Jeśli są na forum to prędzej czy później je przeczytam. Jeśli mam co w nich odpisać, to odpiszę.
 
1988650.png?theme=dark


#12 sebul

    Godlike

  • Przyjaciel

Reputacja: 2 035
Godlike

  • Postów:5 411
  • Steam:steam
  • Imię:Sebastian
  • Lokalizacja:Ostrołęka
Offline

Napisano 14.05.2012 21:39

@sebul Już Ci prezentuję dlaczego nie można tego zrobić na 1 wymiarowej tablicy ;) Przeanalizujmy sytuację: 3 graczy na serwerze, jeden z graczy wchodzi w menu i przez dłuższy czas nic nie wybiera, następnie drugi gracz wychodzi z serwera a na jego miejsce wchodzi inny, dostając ID po poprzednim, gracz 3ci (będący na serwerze już wcześniej) wchodzi w tym momencie w menu (aktualizuje się zaproponowana przez Ciebie tablica) i w tym momencie gracz 1szy decyduje, że przeleje kasę temu graczowi, który wyszedł. Efekt? zabezpieczenie nie zadziałało.

Praktycznie nie możliwe do zrealizowania (znaczy możliwe, ale czy to kiedykolwiek się wydarzy?), dlatego powinno wystarczyć "moje" zabezpieczenie, ale jak dobrze zrozumiałem to masz tutaj w 100% rację.

Jeśli chcesz w info w menu przekazać czasem jakąś inną informację, można zawsze tablicę powiększyć, a nawet pogodzić w niej kilka stringów i danych liczbowych w następujący sposób:

new tablica[64]
copy(nick, tabilca, 31);
copy(sid, tablica[32], 30);
tablica[63] = id;

i w ten sposób przekazać można poprzez info do innej funkcji cały pakiet informacji o graczu ;)

Wiem o tym i nie pisałem, że nie można, ale zauważ, że w takich przypadkach trzeba być uważnym, żeby czegoś nie nadpisać, no i to nie zmienia faktu, że przy wielopoziomowych menu, jest więcej roboty, jeśli zawsze chcemy coś przekazać przez menu, a o to mi właśnie chodzi, żeby było jak najłatwiej, choć dosyć łatwym sposobem było by robić to w ten sposób, w którym można by było używać parse, itp. tak jak napisał goq.
  • +
  • -
  • 0

Posiadam TBM (inaczej PTB), które działa dużo lepiej niż zwykłe PTB, nawet na modach z lvlami. Zainteresowany? Proszę bardzo


#13 GwynBleidD

    Godlike

  • Autor tematu
  • Przyjaciel

Reputacja: 1 869
Godlike

  • Postów:3 066
  • Steam:steam
  • Lokalizacja:Przemyśl
Offline

Napisano 14.05.2012 21:58

Fakt, można użyć parse, jednak dla mnie będzie dalej wygodniejsze moje rozwiązanie, jeszcze mi się nie zdarzyło coś nadpisać, gdyż na oko widać gdzie się dany napis kończy i można zacząć następny, albo wstawić liczbę. Wystarczy dodać początek do końca (wszak 32 jest pierwszym znakiem, maksymalna długość to 30, + 1 znak na null, który właściwie można nadpisać, bo przy wycinaniu tego spowrotem do osobnych zmiennych null zostanie "olany", więc licząc 31 znaków od 32go włącznie) czyli 32+30 i mamy że miejsce ostatniego znaku (nulla) to 62, czyli 63 już jest pusty. Przy zapisie od [0], czyli od początku już sama długość nam określa miejsce zapisania ostatniego znaku.

Budowałem już bardzo wielopoziomowe menu, gdzie po każdym następnym musiałem zapisać wartości wcześniej wybrane, np menu we własnej implementacji bana, najpierw wybór gracza, później powodu i na końcu wybór czasu, dodatkowo dodałem jeszcze 4 menu z wypisanymi wszystkimi danymi i pytaniem czy na pewno chcesz zbanować przy czasie dłuższym niż 1h. Było bardzo proste w realizacji i do ostatecznego handlera trafiały 2 liczby, wartość true/false + string z powodem bana, wszystko przekazywane przez info, działa ślicznie :) Użycie globalnych zmiennych/tablic powodowałoby konflikty gdyby 2ch adminów zachciało na raz zbanować 2 różne osoby i wybór czegoś w menu przez jednego nadpisywałby to, co wybrał wcześniej drugi, w efekcie na końcu wyszedłby niezły miszmasz, np gracz 2 zbanowany z powodem i długością gracza 1. Przy 32 slotowym serwerze i obecnych 5ciu adminach na raz, bez komunikacji między nimi kto banuje w danej chwili błędy nie do uniknięcia. Zastosowanie odpowiednich tablic, aby każdy gracz miał własną komórkę generowałoby dużą ilość niepotrzebnych komórek dla osób, które praw admina nie mają.

A co do opisanej przeze mnie sytuacji, jak najbardziej możliwa, gdyż miałem już z nią do czynienia kilka razy, właśnie w menu do przelewów kasy między graczami, gdzie trzymałem SteamID wszystkich osób w osobnej tablicy, na 32 slotowym, non stop obleganym serwerze. Dzięki za pomysł z userid, zoptymalizuję plugin ;)

Użytkownik GwynBleidD edytował ten post 14.05.2012 21:59

  • +
  • -
  • 0

NIE pomagam na PW. Nie trudź się, na zlecenia nie odpiszę... Od pomagania jest forum.
NIE zaglądam w tematy wysłane na PW. Jeśli są na forum to prędzej czy później je przeczytam. Jeśli mam co w nich odpisać, to odpiszę.
 
1988650.png?theme=dark


#14 sebul

    Godlike

  • Przyjaciel

Reputacja: 2 035
Godlike

  • Postów:5 411
  • Steam:steam
  • Imię:Sebastian
  • Lokalizacja:Ostrołęka
Offline

Napisano 14.05.2012 22:28

Fakt, można użyć parse, jednak dla mnie będzie dalej wygodniejsze moje rozwiązanie, jeszcze mi się nie zdarzyło coś nadpisać, gdyż na oko widać gdzie się dany napis kończy i można zacząć następny, albo wstawić liczbę.

Zawsze wszystko widać na oko, ale jeśli czegoś nie możemy przetestować, czy też nawet skompilować, to o pomyłkę nie jest trudno ^ ^ zresztą ostatnio już parę razy się o tym przekonałem.

A co do opisanej przeze mnie sytuacji, jak najbardziej możliwa, gdyż miałem już z nią do czynienia kilka razy, właśnie w menu do przelewów kasy między graczami

A no o tym nie pomyślałem, jak menu jest dla każdego to jednak prawdopodobieństwo czegoś takiego jest dużo większe.

Co do budowy wielopoziomowego menu, to mam jedno takie menu i jednak musiałbym je przebudować, żeby nie używać zmiennych globalnych, bo jedno menu jest tworzone na początku mapki, gdyż jest stałe, no i dlatego w inny sposób wartości z poprzedniego menu przekazać się nie da, musiałbym te drugie menu tworzyć za każdym razem gdy tylko ktoś coś wybrał w pierwszym menu. Na przyszłość może i zacznę unikać w takich przypadkach zmiennych globalnych, ale nawyki ciężko jest zmieniać :D
  • +
  • -
  • 0

Posiadam TBM (inaczej PTB), które działa dużo lepiej niż zwykłe PTB, nawet na modach z lvlami. Zainteresowany? Proszę bardzo


#15 G[o]Q

    I'm G[o]Q

  • Przyjaciel

Reputacja: 1 344
Godlike

  • Postów:3 563
  • Steam:steam
  • Imię:Krzysiek
  • Lokalizacja:C: / program Files / Valve / Cstrike / G[o]Q.dem
Offline

Napisano 14.05.2012 22:59

sebul to ze robisz menu na początku mapy nie przeszkadza ci w tym zeby potem w polowie mapy je zmienic :P
  • +
  • -
  • 0
Manual ponad wszystko, konsola ponad manual :D :&

Chcesz wysłać do mnie PW ? użyj nazwy GoQ zamiast G[o]Q
Chcesz Kupić moduł płatności via Pukawka,Tserwery, Gamesol, Zabijaka do mojego sklepu? napisz PW cena to tylko 10 zł/sztuka

GG:6022845 (nie pomagam za free osobom ponizej rangi MoD) :D

#16 GwynBleidD

    Godlike

  • Autor tematu
  • Przyjaciel

Reputacja: 1 869
Godlike

  • Postów:3 066
  • Steam:steam
  • Lokalizacja:Przemyśl
Offline

Napisano 14.05.2012 23:01

Dokładnie ;) Zawsze można użyć menu_item_setinfo, o ile dobrze nazwę funkcji pamiętam. Jedynym minusem tutaj jest to, że jest jedno menu dla wszystkich graczy, więc efekt taki, jak przy zmiennych globalnych...

Zresztą to nie problem wyciąć kawałek kodu tworzącego menu i wkleić tuż przed menu_display, a następnie w handlerze dodać menu_destroy w odpowiednich miejscach.

Użytkownik GwynBleidD edytował ten post 14.05.2012 23:03

  • +
  • -
  • 0

NIE pomagam na PW. Nie trudź się, na zlecenia nie odpiszę... Od pomagania jest forum.
NIE zaglądam w tematy wysłane na PW. Jeśli są na forum to prędzej czy później je przeczytam. Jeśli mam co w nich odpisać, to odpiszę.
 
1988650.png?theme=dark


#17 G[o]Q

    I'm G[o]Q

  • Przyjaciel

Reputacja: 1 344
Godlike

  • Postów:3 563
  • Steam:steam
  • Imię:Krzysiek
  • Lokalizacja:C: / program Files / Valve / Cstrike / G[o]Q.dem
Offline

Napisano 14.05.2012 23:15

ja bym poprostu usunął menu i stworzyl nowe z tym czym chce a uchwyt dalej trzymal w globalu ogólnie zasada jest taka ze jak chcemy mieć menu stałe to robimy przy starcie i uchwyt jest zmienną globalną zaś gdy robimy menu dynamiczne to wszystko robimy w zakresie lokalnym lub uzywając zmiennych statycznych nie czytalem tego tutoriala więc nie wiem czy pisales o tym
  • +
  • -
  • 0
Manual ponad wszystko, konsola ponad manual :D :&

Chcesz wysłać do mnie PW ? użyj nazwy GoQ zamiast G[o]Q
Chcesz Kupić moduł płatności via Pukawka,Tserwery, Gamesol, Zabijaka do mojego sklepu? napisz PW cena to tylko 10 zł/sztuka

GG:6022845 (nie pomagam za free osobom ponizej rangi MoD) :D

#18 GwynBleidD

    Godlike

  • Autor tematu
  • Przyjaciel

Reputacja: 1 869
Godlike

  • Postów:3 066
  • Steam:steam
  • Lokalizacja:Przemyśl
Offline

Napisano 14.05.2012 23:45

Akurat o tym się nie rozpisywałem, chociaż można o to uzupełnić tutorial, a polecam go przeczytać ;) Może dowiesz się ciekawych rzeczy :P Usunięcie starego i zrobienie nowego menu, ale dalej trzymanie go w zmiennej globalnej ma taki sam efekt jak opisane wcześniej przeze mnie menu_item_setinfo, ze względu na to właśnie, że używamy jednego menu (przez co jednego zestawu zmiennych) dla wszystkich graczy. Co rodzi tylko same problemy, gdy dostęp do menu ma kilka osób... Oczywiście tylko w sytuacji, gdy przy każdym wywołaniu menu coś w tych zmiennych (lub w całym menu) zmieniamy. Nadaje się to tylko do całkowicie statycznych menu, bez jakichkolwiek pomocniczych wartości czy zmian w strukturze menu, lub gdy do menu ma dostęp w danym czasie wyłącznie jedna osoba.

Użytkownik GwynBleidD edytował ten post 14.05.2012 23:47

  • +
  • -
  • 0

NIE pomagam na PW. Nie trudź się, na zlecenia nie odpiszę... Od pomagania jest forum.
NIE zaglądam w tematy wysłane na PW. Jeśli są na forum to prędzej czy później je przeczytam. Jeśli mam co w nich odpisać, to odpiszę.
 
1988650.png?theme=dark


#19 sebul

    Godlike

  • Przyjaciel

Reputacja: 2 035
Godlike

  • Postów:5 411
  • Steam:steam
  • Imię:Sebastian
  • Lokalizacja:Ostrołęka
Offline

Napisano 15.05.2012 07:45

sebul to ze robisz menu na początku mapy nie przeszkadza ci w tym zeby potem w polowie mapy je zmienic :P

Tak, ale po co to robić w ten sposób, skoro wszystkie itemy w menu musiały by być zmienione? Jak już się bawić w dynamiczne menu, to po prostu najlepiej robić je za każdym razem od nowa, a nie zmieniać je w trakcie, Do tego działanie było by praktycznie takie samo jak przy zmiennej globalnej, co zostało już napisane. I ja tu nie pisałem, że to jest nie możliwe do zrobienia (nie w tym sensie) lub trudne do zrobienia, nawet napisałem co bym musiał zrobić, tylko po co mam coś zmieniać, skoro to jest menu adminów i nigdy nie zdarzyło się coś takiego (i pewnie się nie zdarzy) jak przy tym, opisanym wcześniej, przekazywaniu kasy pomiędzy graczami.
  • +
  • -
  • 0

Posiadam TBM (inaczej PTB), które działa dużo lepiej niż zwykłe PTB, nawet na modach z lvlami. Zainteresowany? Proszę bardzo


#20 Cypis'

    Master

  • Przyjaciel

Reputacja: 1 161
Super Hero

  • Postów:965
  • GG:
  • Steam:steam
  • Lokalizacja:polska
Offline

Napisano 15.05.2012 21:38

Ja się doczepie do jednego menu_addtext - nie działa on na amxx 1.8.1 więc można napisać że dodając znak nowej lini (^n) do poprzedniego menu_additem uzyskamy ten sam efekt jak byśmy dodali menu_addtext
  • +
  • -
  • 0




Użytkownicy przeglądający ten temat: 0

0 użytkowników, 0 gości, 0 anonimowych