Skocz do zawartości

d0naciak

Właściciel Sieci
  • Liczba zawartości

    22
  • Rejestracja

  • Ostatnia wizyta

  • Wygrane w rankingu

    6

Ostatnia wygrana d0naciak w dniu 26 Stycznia

Użytkownicy przyznają d0naciak punkty reputacji!

Reputacja

61 Klawiaturowy klikacz

1 obserwujący

Ostatnie wizyty

Blok z ostatnimi odwiedzającymi dany profil jest wyłączony i nie jest wyświetlany użytkownikom.

  1. Co to są KeyValues? KeyValues to prosta struktura bazująca na organizacji "drzewkowej" która zawiera zagnieżdżone w sobie sekcje które to zawierają klucze i wartości. Dla wzrokowców i objaśnienia sprawy, najprostsza struktura KeyValues wygląda w ten sposób: "sekcja" { "klucz" "wartosc" } Jak napisałem na samym początku, sekcje mogą być w sobie zagnieżdżone, czyli do sekcji możemy dopisać kolejną sekcję, do niej kolejną, itd. Przykład: "sekcja1" { "sekcja2" { "klucz" "wartosc" } } Przy budowaniu struktury KeyValues warto zaznaczyć, że nazwy sekcji i kluczy nie mogą się powtarzać w obrębie danej sekcji. Trochę zagmatwane, ale mówiąc prościej tworząc sekcję "admin" nie możemy później wewnątrz tej sekcji stworzyć np. 2 razy sekcję "Kowalski", czy 2 razy klucza "Kowalski", nie powinniśmy też tworzyć klucza "Kowalski" a potem sekcji "Kowalski" czy też odwrotnie - myślę, że zrozumiałe. Dodatkowo do KeyValues możemy swobodnie dodawać komentarze. Komentarze pozwalają Nam dodawać tekst, który zostanie pominięty przy wczytywaniu KeyValues poprzez plugin. Dodajemy je poprzez użycie dwóch slashy (//) oraz wypisaniu za nimi jakiegoś tekstu. Komentarz jest jednolinijkowy, czyli od kolejnego wiersza będziemy mogli dalej budować naszą strukturę. "sekcja" { "klucz1" "wartosc1" //To jest komentarz. Tekst ten zostanie pominiety przy wczytywaniu KeyValues przez plugin SourceMod "klucz2" "wartosc2" } Z KeyValues mogłeś(aś) się już spotkać wcześniej, np. przy konfigurowaniu połączenia z bazą danych w pliku addons/sourcemod/configs/databases.cfg. Dla przypomnienia taki plik wygląda mniej więcej tak: "Databases" { "driver_default" "mysql" // When specifying "host", you may use an IP address, a hostname, or a socket file path "default" { "driver" "mysql" "host" "localhost" "database" "db" "user" "root" "pass" "" //"timeout" "0" //"port" "0" } "storage-local" { "driver" "sqlite" "database" "sourcemod-local" } } Jak pracować z KeyValues w pluginie SourceMod? Na początku przyjmijmy pewne założenia. Mianowicie napiszemy sobie plugin, który będzie tworzył główne menu serwera. Plugin ten będzie wywoływał komendę w konsoli gracza po naciśnięciu konkretnej opcji w menu. Nasz plik KeyValues będzie w addons/sourcemod/configs, nazwiemy go main_server_menu.ini. Jego struktura będzie wyglądała w ten sposób (wiem, można by to zrobić lepiej): "MainServerMenu" { "sm_vip" { "name" "Sprawdź opis VIP'a" "command" "sm_vip" } "res" { "name" "Menu RoundSoundów" "command" "res" } "rs" { "name" "Resetuj statystyki" "command" "rs" } } Na początku zadeklarujmy zmienną globalną która będzie uchwytem dla naszego menu głównego oraz od razu dodajmy RegConsoleCmd do OnPluginStart: Menu g_mainServerMenu; public void OnPluginStart() { RegConsoleCmd("sm_menu", cmd_MainServerMenu); } public Action cmd_MainServerMenu(int client, int args) { g_mainServerMenu.Display(client, MENU_TIME_FOREVER); return Plugin_Handled; } Następnie zbudujmy funkcję, która będzie odpowiedzialna za stworzenie menu na podstawie naszych KeyValues. Niech to będzie funkcja BuildMenu void BuildMenu() { // kodzik... } Na samym jej początku stworzymy nasze menu: //tworzymy menu g_mainServerMenu = new Menu(MainServerMenu_Handler); g_mainServerMenu.SetTitle("Główne menu serwera", MENU_ACTIONS_ALL); Następnie stworzymy uchwyt do KeyValues oraz wczytamy jego strukturę z naszego pliku konfiguracyjnego: //budujemy sciezke do pliku addons/sourcemod/configs/main_server_menu.ini char path[256]; BuildPath(Path_SM, path, sizeof(path), "configs/main_server_menu.ini"); //tworzymy KeyValues oraz importujemy strukture z pliku KeyValues keyValues = new KeyValues("MainServerMenu"); keyValues.ImportFromFile(path); Warto powiedzieć. że KeyValues wcale nie muszą wykorzystywać żadnego pliku. Można operować chociażby na strukturze podanej jako ciąg znaków wczytanej z zewnętrznego źródła (np. zawartość zewnętrznej strony WWW). Jednak najczęściej oczywiście struktura jest wczytywana z pliku, tak jak w przykładzie wyżej. Co jeszcze jest istotne, to przy deklaracji new KeyValues jako paramtetr podajemy nazwę pierwszej sekcji w naszym pliku, znaną również jako sekcja główna czy węzeł główny (więcej niżej). Mamy już wczytany pliczek do uchwytu, teraz trzeba by się odpowiednio po tej całej strukturze poruszać, a potem wczytać odpowiednie wartości do menu. Przy poruszaniu się po pliku należy wiedzieć, że: Sekcja to też w pewnym sensie klucz, o czym warto pamiętać przy poruszaniu się po strukturze. Sekcja to taka oddzielna nazwa dla kluczy, które posiadają w sobie jeszcze inne klucze. Poruszając się po pliku mamy do czynienia z pozycją. Pozycja określa nam na którym poziomie podsekcji jesteśmy (inaczej poziom zagnieżdżenia) oraz na którym kluczu w danej sekcji jesteśmy. Mówiąc o pozycji mamy zatem do czynienia z dwoma wartościami. Jak to wygląda praktyce? A no tak: "MainServerMenu" //sekcja główna (węzeł główny) { "sm_vip" //pierwszy klucz w pierwszym poziomie zagnieżdżenia { "name" "Sprawdź opis VIP'a" //pierwszy klucz w drugim poziomie zagnieżdżenia "command" "sm_vip" //drugi klucz w drugim poziomie zagnieżdżenia } "res" //drugi klucz w pierwszym poziomie zagnieżdżenia { "name" "Menu RoundSoundów" //pierwszy klucz w drugim poziomie zagnieżdżenia "command" "res" //drugi klucz w drugim poziomie zagnieżdżenia } "rs" //trzeci klucz w pierwszym poziomie zagnieżdżenia { "name" "Resetuj statystyki" //pierwszy klucz w drugim poziomie zagnieżdżenia "command" "rs" //drugi klucz w drugim poziomie zagnieżdżenia } } Podstawowe funkcje do poruszania się po KeyValues: GotoFirstSubKey(); // Przesuwa pozycje do pierwszej podsekcji (poziom zagniezdzenia nizej) // Zwraca false w przypadku nieznalezienia podsekcji GotoNextKey(); // Przesuwa pozycje do kolejnego klucza/sekcji w danej sekcji // Zwraca false w przypadku nieznalezienia kolejnego klucza GoBack(); // Przesuwa pozycje o poziom zagniezdzenia wyzej. // Zwraca false, kiedy nie da sie juz wyzej przesunac (np. jestesmy w wezle glownym) Rewind(); // Ustawia pozycje wezla glownego. Podobny cel mozna osiagnac poprzez // uzywanie GoBack dopoki nie zwroci false, jednak ta funkcja jest optymalniejsza. JumpToKey(const char[] key, bool create=false); // Przenosi nas do klucza w danej sekcji o podanej nazwie w parametrze "key" // W przypadku create=true oraz jezeli dany klucz nie zostanie znaleziony, funkcja ten klucz stworzy. // Zwraca true w przypadku znalezienia klucza, false jezeli klucza nie znaleziono Pominąłem parametry które mogły by być trudne do zrozumienia a mają one swoje domyślne wartości. Dla ciekawskich wszystkie i w pełni opisane funkcje można znaleźć w dokumentacji. Okejj, więc co dalej po otwarciu pliku? Musimy przejść o jedno zagnieżdżenie niżej, a więc kolejny skrawek kodu będzie wyglądać tak: //nie znaleziono zadnej podsekcji? Plik jest nieprawidłowy, koniec :/ if (!keyValues.GotoFirstSubKey()) { PrintToServer("*** I had a problem while building a menu :/ Check main_server_menu.ini"); delete keyValues; return; } Po prawidłowym przejściu niżej, Nasza pozycja wygląda teraz tak: "MainServerMenu" //przed GotoFirstSubKey bylismy tutaj { "sm_vip" //po GotoFirstSubKey jestesmy tutaj { "name" "Sprawdź opis VIP'a" "command" "sm_vip" } "sm_res" { "name" "Menu RoundSoundów" "command" "sm_res" } "sm_rs" { "name" "Resetuj statystyki" "command" "sm_rs" } } Co teraz? Musimy wczytać dane z danej sekcji, dodać opcję do menu i przejść do kolejnego klucza (w Naszym wypadku kolejnej sekcji). Skorzystamy z pętli do while: char command[64], itemName[64]; do { //wczytujemy dane z danej sekcji keyValues.GetString("command", command, sizeof(command)); keyValues.GetString("name", itemName, sizeof(itemName)); //dodajemy opcje do menu g_mainServerMenu.AddItem(command, itemName); } while (keyValues.GotoNextKey()); //przechodzimy do kolejnej sekcji, dopoki te sekcje nie skoncza sie I to by było na tyle z wczytywanie, nasze menu jest już zbudowane ^^ Nie zapomnijmy o zamknięciu uchwytu no iii dajmy odpowiednie info serwerowi: //info dla serwera oraz oproznianie zmiennej kv delete keyValues; PrintToServer("*** Main server menu has been built"); Funkcję BuildMenu możemy zamknąć, a pod nią dodajmy funkcję Handler do naszego menu. Będziemy tam w momencie wybrania opcji wpisywać do konsoli gracza daną komendę zapisaną pod "info" tej właśnie opcji: //obsluga menu public int MainServerMenu_Handler(Menu menu, MenuAction action, int param1, int param2) { switch (action) { case MenuAction_Select: { int client = param1; //wczytujemy komende z pola "info" z danej opcji w menu oraz wywolujemy komende w konsoli char info[64]; menu.GetItem(param2, info, sizeof(info)); ClientCommand(client, info); } } } W OnPluginStart należy jeszcze wywołać funkcję od budowania menu: public void OnPluginStart() { RegConsoleCmd("sm_menu", cmd_MainServerMenu); BuildMenu(); } Nasz plugin jest gotowy Kod *.sp oraz plik *.ini podaję w załącznikach -> main_server_menu.ini server_menu.sp Co jeszcze warto wiedzieć? Do wczytywania wartości z klucza mamy kilka funkcji, które odpowiadają danemu typowi wartości. Możemy np. wartość wczytać od razu w type int, słuzy do tego funkcja GetNum która zwraca wartość klucza. Jest wiele innych ciekawych funkcji jak GetFloat, GetColor, itd. - więcej w dokumentacji Strukturę można zmieniać, a zmiany potem zapisać poprzez funkcję ExportToFile. Są odpowiednie funkcje do usuwania kluczy, ustawiania ich wartości, itd. Jak wyżej - więcej info na ten temat można znaleźć w dokumentacji KeyValues nie powinny być zbyt wielkie. Niedopuszczalne jest skorzystanie z KeyValues w celu zapisywania ilości zabójstw graczy. Przy tak dużej ilości danych zdecydowanie lepszym rozwiązaniem jest baza danych. Wyjątkiem może być plik w którym tych graczy jest mniej, np. plik z graczami którzy dostają specjalny bonus. Plików KeyValues staraj się nie otwierać zbyt często, najlepiej zrobić to maks. raz na mapę bądź też poprzez komendę do której dostęp ma tylko opiekun serwera. Zadanie domowe! Usuń klucz "command" i zamiast wczytywania go wykorzystaj funkcję GetSectionName dzięki której wczytasz nazwę sekcji, a co za tym idzie od teraz komendę będziesz podawać właśnie w nazwie sekcji. Rozwiązaniem możesz się pochwalić w tym temacie
  2. Przy wczytaniu pluginu gdzie jest pętla po graczach i wczytanie ich ciasteczek wypadałoby sprawdzić jeszcze czy AreClientCookiesCached
  3. Chętnie kupię Serwer CS:GO Co najwyżej 1200 w GT Mod nie ma znaczenia Serwer CS 1.6 Co najwyżej 1200 GT Mod nie ma znaczenia Hosting pukawka bądź 1s1k Kontakt wyłącznie na PW bądź GG 53722333
  4. @Mesharsky nie ma co ujmować koledze, pierwszy plugin a wygląda lepiej niż mój pierwszy udostępniony publicznie ^^ Każdy kiedyś zaczynał, pracuj tak dalej a będą z Ciebie ludzie Ode mnie dodam, że tutaj zamiast: bool g_bPlayerWczytane [MAXPLAYERS]; powinno być bool g_bPlayerWczytane [MAXPLAYERS+1]; Gdyż w przypadku gdy serwer będzie pełny, dla gracza z ostatnim client ID braknie miejsca w tablicy
  5. Opis Jest to oczywiście znany Cod Mod napisany w 100% przeze mnie. Myślę, że jest on optymalniejszy niż pozostałe modyfikacje jakie można znaleźć. Rozwijanie paczki zostało zawieszone, gdyż serwer po prostu upadł, dlatego też kod nie zawsze jest najlepszy, jednak postanowiłem podzielić się z Wami tym, co udało mi się do tej pory napisać. Więcej niżej: - 20 klas zwykłych, 5 klas premium (kliknij, aby zobaczyć ich opis) - 56 perków (kliknij, aby zobaczyć ich opis) - klasy oraz perki poukładane są w menu wg. alfabetu, aby ułatwić poruszanie się w nim - system monet wstawiony w miejsce dolarów - umiejętności klas i perków napisane osobno, co pozwala na łatwą edycję oraz zmniejszenie ilości błędów wynikających z nakładających się umiejętności - standardowo użycie umiejętności klas pod E, umiejętności perków pod G - free level - prosty system cooldownów dla umiejętności wraz z efektem dźwiękowym przy ich odblokowaniu - system misji, 20 zadań podzielonych na 4 rozdziały - system klanów wraz z rangami, statystykami, wojnami oraz topką klanów - sklepik serwerowy z doświadczeniem, statystykami, extra itemami, trailami, sprayami - skrzynki wypadające z graczy - losowy kod do przepisania na czacie - daj/wymień perk wraz z blokadami - rynek z perkami - blokada perków dla danych klas - nocny exp - gotowy VIP (flaga custom 1) wraz z opisem - rozbudowane menu pomocy dla początkujących - nagroda dla TOP 3 graczy co mapę Wymagania - baza danych MySQL Komendy gracza sm_binds, sm_bindy - pomoc w bindach umiejętności sm_d, sm_drop - wyrzucenie perku sm_k, sm_klasa - wybór klasy sm_klasy - opis wszystkich klas sm_p, sm_perk - opis perku sm_perki - opis wszystkich perków sm_ranklvl - ranking poziomu sm_resetstat, sm_resetstats - reset statystyki sm_stats, sm_staty - menu rozdawania statystyk sm_top15lvl - top 15 poziomów sm_useitem, sm_useperk - użycie perku sm_useskill - użycie umiejętności klasy sm_sklep - otwiera sklepik sm_misje - otwiera menu misji sm_klan - otwiera menu klanów sm_daj - menu dawania perka sm_wymien - menu wymiany perka sm_bwymiane - blokada wymiany perkiem sm_rynek - rynek perków sm_vip - opis VIP'a sm_pomoc - menu pomocy Komendy admina cod_givecoins <nick> <amount> - dodaje monety graczowi cod_givelvl <nick> <amount> - dodaje poziom do aktualnej klasy gracza cod_givexp <nick> <amount> - dodaje doświadczenie do aktualnej klasy gracza cod_setcoins <nick> <amount> - ustawia monety graczowi cod_setlvl <nick> <amount> - ustawia poziom aktualnej klasy gracza cod_setperk <nick> <perk name> [perk value] - ustawia perk graczowi cod_setxp <nick> <amount> - ustawia doświadczenie aktualnej klasy gracza Galeria Download https://github.com/d0naciak/SM-Call-Of-Duty-Mod/releases Instrukcję instalacji można znaleźć w środku
  6. No nie jest to do końca dekompilator, nie wiedziałem że plikami w mapie można sobie żonglować, mniejsza ? Najważniejsze że udało się rozwiązać problem, radar działa także wielkie dzięki, można zamknąć ?
  7. Jak wrzucić? Jedyny działający "dekompilator" jaki znalazłem to BSPSource, dzięki niemu wyciągnąłem radar z mapy, jednak nic do mapy wrzucić dzięki temu programowi to z tego co widzę nie mogę, no chyba że ja o czymś nie wiem ?
  8. Zmieniłem nazwę mapy i wyeksportowałem radar do osobnego pliku. Pytanie jak wymusić u gracza pobieranie tego radaru, bo sam z siebie nie chce się pobierać.
  9. 1. Jak trzeba podać rozmiar tablicy, podają o jeden punkcik mniej, przykład: char name[64]; Format(name, 63, "mójNick"); Gdzie prawidłowa forma to: char name[64]; Format(name, 64, "mójNick"); A najlepszym nawykiem jest: char name[64]; Format(name, sizeof(name), "mójNick"); 2. Plugin niedostosowany do załadowania/wyładowania w trakcie gry. Warto w OnPluginStart wywoływać takie wydarzenia jak OnClientAuthorized, OnClientPutInServer itd., a w OnPluginEnd wywoływać OnClientDisconnect. Mega mało ludzi tak robi, bo nauczeni są restartować serwer przy wgraniu pluginu, źleeee. Co za tym idzie drugi błąd, ale pozwolę sobię go opisać, czyli pośrednie zapytanie SQL (threaded query) w OnPluginEnd. Niestety ale wtedy do zapisu może nie dojść. 3. Na siłę używanie bezpośrednich zapytań SQL (non-threaded query) bądź korzystanie ze SQLite, bo działają natychmiastowo. Niestety ale zapytania bezpośrednie potrafią nieźle zamulić serwer. Dopuszcza się używanie ich wtedy, kiedy np. dane zapisywane są przy wyładowaniu pluginu o czym napisałem wyżej, jednak kiedy jest okazja warto zawsze korzystać z "SQL_TQuery". SQLite jest dobre o ile jest tam dość mało danych, nie opłaca się używać SQLite kiedy dane są przypisane do np. graczy, wtedy przepełnienie bazy następuje dosyć szybko, a co za tym idzie serwer doznaje pojedynczych ścinek które trwają nawet po 0.5s, czyli jest to bardzo dokuczliwe.
  10. Witam, jest opcja powiązania plików do mapy, tj. wymuszanie ich pobierana na danej mapie za pomocą jakiejś konfiguracji? Wiem, że można to zrobić pluginem, ale zastanawiam się czy istnieje jakiś prostszy sposób. Pozdrawiam ?
  11. Dobra, problem rozwiązałem inaczej, podzielę się doświadczeniami ? Sporo googlowałem, i znalazłem między innymi takie rozwiązanie: https://github.com/sbpp/sourcebans-pp/issues/367 To rozwiązanie było często pomocne z tego co wyczytałem, ale jednak mi praktycznie nie pomogło, ale podsyłam gdyż komuś może się to przydać. Zdecydowałem się zatem na metodę komentowania kolejno linijek od tych najbardziej podejrzanych i ustaliłem, że problem siedzi w następującym zapytaniu: $submission = $GLOBALS['db']->Execute('UPDATE `'.DB_PREFIX.'_submissions` SET archiv = \'3\', archivedby = '.($userbank->GetAid()<0?0:$userbank->GetAid()).' WHERE archiv = \'0\' AND (SteamId IN((SELECT authid FROM `'.DB_PREFIX.'_bans` WHERE `type` = 0 AND `RemoveType` IS NULL)) OR sip IN((SELECT ip FROM `'.DB_PREFIX.'_bans` WHERE `type` = 1 AND `RemoveType` IS NULL)))'); Wycinek z includes/system-functions.php Zdecydowałem się więc po prostu opróżnić tabelę sb_submissions, a także wyłączyć opcję Submit a ban w panelu administracji, gdyż i tak wszystko rozwiązujemy przez forum. Problem poniekąd można uznać za rozwiązany, jednak nie zagłębiałem się w samo zapytanie, bo najprawdopodobniej gdzieś w nim mimo wszystko jest problem (chociaż w sumie może problem jest głębszy, nie mam pojęcia xD). Dodatkowo dokonałem eksportu tabeli, żeby być może w czasie wolnym (w co szczerze wątpię xD) po prostu ustalić gdzie jest problem. Spróbuję po prostu zgłosić ten problem na githubie, kto wie... coś pomogą? ?
  12. Witam, mam niemały problem z SB, mianowicie poruszanie się po banach trwa zdecydowanie za długo. Przy juz 3k banów samo wyszukiwanie potrafi zajmować nawet pół minuty, przy mniejszej ilości banów tego problemu nie ma, jednak wieczne ich usuwanie jest nie dość że mało zautomatyzowanym rozwiązaniem to po prostu nie tędy droga. Słyszałem, że może zależeć to od wersji SB, czy też wersji MySQL na serwerze, jednak kombinowałem na różnorakie sposoby i do tej pory bez skutku. Z góry dziękuję za pomoc, pozdrawiam.
×
×
  • Dodaj nową pozycję...