Jump to content
  • Chmurka
  • Boróweczka
  • Jabłuszko
  • Limonka
  • Czekoladka
  • Węgielek

Search the Community

Showing results for tags 'sourcemod'.



More search options

  • Search By Tags

    Type tags separated by commas.
  • Search By Author

Content Type


Forums

  • Nasze Sprawy
    • Nowości
    • Dyskusje
    • Propozycje
    • Przywitaj się!
  • Sourcemod Scripting
    • Artykuły, poradniki, tutoriale
    • Pytania na temat kodowania
    • Problem z kodem pluginu
    • Prośby o przerobienie pluginu
    • Gotowe funkcje
    • Koduj z Magnetem
  • Konfiguracja pluginów
    • Artykuły, poradniki i tutoriale
    • Szukam pluginu
    • Duże modyfikacje
    • Zbiór pluginów
    • Extensions
    • Gotowe paczki serwerowe
  • Konfiguracja serwera
    • Artykuły, poradniki, tutoriale
    • Pytania
    • Problemy
    • Ochrona
    • Metamod
  • Counter-Strike: Global Offensive
    • Nowości
    • Artykuły, poradniki, tutoriale
    • Pytania
    • Problemy
    • Pliki
    • Wasza twórczość
    • Publikacje serwerów
  • Hostingi serwerów
    • Oferty firm
    • Opinie o hostingach
    • Pytania
  • Plac zabaw
    • Luźne rozmowy
    • Szukam ekipy
    • Rynek
    • Opinie o ludziach
    • RoundSoundy
  • Archiwum
    • Przestarzałe tematy
    • Kosz

Find results in...

Find results that contain...


Date Created

  • Start

    End


Last Updated

  • Start

    End


Filter by number of...

Joined

  • Start

    End


Group


O mnie

Found 39 results

  1. O Pluginie: Wprowadza na serwer system rang. Wprowadza na serwer walutę jaką są złote naboje. Wszystko konfiguruje się poprzez 3 różne pliki. Komendy: !ap - Panel administracyjny !adminpanel - Panel administracyjny !reloadcfg - Przeładowanie configów !ranks - Główne menu rang !rank - Główne menu rang !ranga - Główne menu rang !rangi - Główne menu rang Instalacja: Standardowa Zrzuty ekranu: Podłączenie do bazy danych: Dodatkowe informacje: Plugin nie był testowany na żadnym serwerze z graczmi, więc każdy błąd proszę o zgłaszanie w tym temacie 😉 . Do pliku admin_overrides.cfg należy dodać: "sm_oVip" "flagi vipa" Download: yRanks_Go-Code.rar
  2. Typ paczki: Only Awp Pluginy w paczce: Silnik Odznaki RankMe Vip VipInfo Kontakt Informacja o połączeniu System monet Screeny: Cena: 100 zł. Kontakt: https://steamcommunity.com/id/yamakashisteam2 Dodatkowe informacje: Wszystkie znajdujące się w paczce pluginy zostały napisane przeze mnie. Oferuję pomoc z wgraniem paczki na serwer oraz podpięciem pluginów pod bazę danych Po zakupie paczki nabywca otrzymuje wszystkie kody źródłowe Zapraszam do zakupu pluginu współgrającego z paczką >>GoMod<< . W celu zakupu należy kontaktować się ze mną na pw forum lub steam. Jeżeli ktoś posiada jakieś pytania dotyczące zakupu z chęcią odpowiem na pw.
  3. Witam, chciałbym się dowiedzieć czy można kogoś wyłączyć z rozgrywki. Chodzi mi o to że na niektórych serwerach surf+rpg możesz powrócić do życia po śmierci z samym nożem lecz nie możesz ich zranić oraz inni cię nie widzą. Jak wygląda taki plugin czy też jaka funkcja jest do tego używana. Mnie by ciekawiła funkcja dzięki której byś się mógł znów pojawić ale tak żeby inni ciebie widzieli. Jest mi to potrzebne do zrobienia specjalnego pluginu. Za odpowiedzi z góry dziękuję ?
  4. Witam drogą społeczność tego forum! Szukam technika SourceMod ze sporym bagażem doświadczeń w tejże dziedzinie. W niedługim czasie planuję rozpocząć prace nad serwerem CS:GO, na temat którego chętnie opowiem osobie zainteresowanej współpracą na dłuższą metę. Z uwagi na fakt, iż szukam osoby doświadczonej, jestem w stanie zaoferować wynagrodzenie za współpracę, co jest raczej oczywiste. Jeśli nie jesteś pewien/pewna swoich umiejętności bądź nie potrafisz programować pluginów - nawet nie pisz, bo stracimy tylko cenny czas. Kontakt: Wyłącznie przez platformę Steam < Kliknij
  5. Opis Plugin tworzy dodatkową rundę nożową po rozgrzewce(warmup) i przed rundami. Drużyna, która wygra tę rundę może wybrać po której stronie chce zaczynać mecz. Wybór odbywa się poprzez menu do głosowania. Cvary Changelog Download KnifeRound.7z knife_round.sp Inne Plugin jest przeze mnie wspierany, gdyby pojawiły się jakieś bugi lub sugestie chętnie pomogę/wysłucham jeśli napiszecie poniżej ? Support Aktualnie support tego pluginu jest prowadzony przez @Vasto_Lorde
  6. Usuwanie niepotrzebnego, zbędnego kodu z naszego projektu jest istotnym elementem dobrej opieki nad nim. Ale są ludzie, którzy powiedzą "Hej! Panie! Ja tu się namęczyłem z pisaniem tego kodu i NIE MA OPCJI żebym go teraz kasował nawet jeśli już go nie używam". Ten artykuł ma wszystkich upartych przekonać, dlaczego martwy kod trzeba zakopywać głęboko klawiszem backspace. Nad projektem może pracować więcej niż jedna osoba. A jeśli produkujesz oprogramowanie open-source, to kod będzie przeglądać o wiele więcej ludzi niż Twój zespół programistyczny. Jak dobrze wiemy kod jest przede wszystkim komunikacją między programistami, a to, że działa i spełnia swoje zadania jest sprawą drugorzędną. Obca osoba czytając martwy kod musi poświęcić dwa razy więcej czasu niż w przypadku kodu który jest w użytku ponieważ a) Musi zrozumieć jak działa b) Musi zrozumieć dlaczego ten kod nie jest używany i czy na pewno nie jest nigdzie używany i może go usunąć; Za każdym razem przeglądając kod po raz dziesiąty czy setny, ktoś spędzi dłuuugie sekundy myśląc sobie "ah, to tu jest martwy kod, moje oczy muszą go ominąć". Taki kod to po prostu hałas dla oczu. Niepotrzebny żwir na naszym asfalcie. Dlaczego na naszym płaskim, idealnym asfalcie jest wysypany żwir? To na pewno nie jest sposób w jaki chcemy produkować a tym bardziej przeglądać kod; Martwy kod jest martwy. Nie jest rozwijany. Został pozostawiony sam sobie kilka, kilkadziesiąt, kilkaset iteracji temu. Programista może użyć go bez wiedzy, że jest martwy. "Jest tam, więc czemu miałby być źle napisany?" Otóż nierozwijany kod zostawiony sam sobie może już nie spełniać obecnych standardów projektu, lub nawet jego autor mógł go nie dokończyć. Wtedy przy jego użyciu mogą wystąpić konsekwencje - bugi Jeśli używasz jakiegokolwiek systemu kontroli wersji kodu i to na Ciebie spada odpowiedzialność za utrzymanie i konserwację kodu (zachowując jednocześnie martwy kod w projekcie), to masz więcej linii kodu do przejrzenia, więcej odpowiedzialności na Twoich barkach oraz większe pole do popisu dla błędów w zarządzaniu kodem Konsekwencją chomikowania martwego kodu jest to, że ten kod się kumuluje. Normalnie, zachowuje się tylko najpotrzebniejsze rzeczy, tylko rzeczy używane, tylko rzeczy które spełniają jakąś rolę w naszym programie. Dlatego opiekujemy się nim, optymalizujemy go, refaktorujemy. W przeciwieństwie do martwego kodu. Ten, kumuluje się i zbiera, rosnąc diametralnie, a swoim rozmiarem zniechęca maksymalnie kogokolwiek, żeby zrobił co trzeba - przejrzał jeszcze raz kod, zrozumiał go i wyrzucił do kosza Nie martw się, że kod który napisałeś zostanie skasowany, bo nie jest już potrzebny. W dzisiejszych czasach praktycznie zawsze używa się systemu kontroli wersji (np. GIT). Twój kod, który kiedyś w swojej świetności działał idealnie, jest zakopany gdzieś w commitach. Nie ma powodu żeby za nim płakać. Z czasem, szansa na ponowne użycie nieużywanego kodu maleje. Nie musisz go trzymać w każdej iteracji. Odpuść, zrób przysługę sobie w przyszłości i skasuj go. Jeśli był naprawdę ważny i kiedyś zdarzy się sytuacja, gdzie będziesz potrzebował tego kodu, odkopiesz go z czeluści GITa. Tutaj widzę dobrą okazję na przedstawienie jednej z reguły tworzenia oprogramowania w trybie extreme programming: YAGNI (ang. You aren't gonna need it). Mówi nam ona o tym, że mamy pisać tylko i wyłącznie funkcjonalności których potrzebujemy teraz. Nie mamy przewidywać jakich funkcjonalności będziemy potrzebować. Skupiamy się na chwili obecnej. Można to też interpretować w drugą stronę - jeśli czegoś już nie potrzebujesz to skasuj to natychmiast Bibliografia https://stackoverflow.com/questions/15699995/why-unused-code-should-be-deleted https://en.wikipedia.org/wiki/You_aren't_gonna_need_it https://www.infoq.com/news/2017/02/dead-code/
  7. Cześć. Wgrywam sobie metamoda i sourcemoda (najnowsze) do folderu z CS:GO, włączam CS:GO z komendą -insecure, wbijam na serwer z botami, wpisuję komendę w konsolę "sm exts list" i wyskakuje to: <FAILED> file "": Prodecura inicjowania biblioteki dołączanej duynamicznie (DLL) nie powiodła się. Co robić gocodziarze?
  8. Przed tłumaczeniem sprawdź czy plugin nie ma pliku *.phrases.txt odpowiadającego za tłumaczenie tekstów. Poradnik na temat tłumaczenia w pliku phrases.txt znajdziesz tutaj. W przypadku, gdy plugin nie posiada tego pliku, a wyświetla graczowi jakieś informacje, będzie go trzeba przetłumaczyć. Można to zrobić na dwa sposoby. Pierwszy, którego tutaj nie omówię, to przerobienie pluginu tak, by korzystał z pliku phrases.txt. Drugi, to na sztywno zmienienie fraz wyświetlanych w innym języku na frazy w naszym języku. 1. Plugin Informacje o Serwerze. Linia 24: CPrintToChat(client, "{darkred}Server name :{default} %s", sBuffer) Linia 37: CPrintToChat(client, "{darkred}Server IP: {default}%d.%d.%d.%d:%d", pieces[0], pieces[1], pieces[2], pieces[3], port) Linia 72: CPrintToChat(client, "{DarkRed}Timeleft:{default} %s", sBuffer) Interesują nas zaznaczone na kolorowo frazy zamieszczone w cytacie. Wynik końcowy będzie następujący: Linia 24: CPrintToChat(client, "{darkred}Nazwa serwera :{default} %s", sBuffer) Linia 37: CPrintToChat(client, "{darkred}IP serwera: {default}%d.%d.%d.%d:%d", pieces[0], pieces[1], pieces[2], pieces[3], port) Linia 72: CPrintToChat(client, "{DarkRed}Czas do końca mapy:{default} %s", sBuffer) Jak można zauważyć, zmieniły się tylko angielskie wyrazy. Specjalne znaki takie jak {darkred} czy %d zostawiamy w spokoju, są to informacje potrzebne pluginowi w jaki sposób ma wyświetlić wiadomość. Po zmianach plik zapisujemy kompilujemy i wrzucamy na serwer 2. Plugin Block sm plugins Linia 34: SetFailState("Failed to find offset for ClientPrintf"); Linia 133: PrintToConsole(client, "\t\tNo chance\n"); Linia 75: BuildPath(Path_SM, g_sLogs, sizeof(g_sLogs), "logs/sbp-%s.log", sDate); Linia 95: else if(StrContains(sBuffer, "To see more, type \"sm plugins") != -1) Robimy właściwie to samo, uważając na znaki specjalne \t. Natomiast w liniach 75 oraz 95 NIC nie tłumaczymy! Musimy uważać tłumacząc w ten sposób pluginy, gdyż niekiedy angielski tekst w cytatach nie wyświetla się użytkownikom a jego zmiana może spowodować zepsucie pluginu! Wynik końcowy: Linia 34: SetFailState("Nie znaleziono offsetu dla ClientPrintf"); Linia 133: PrintToConsole(client, "\t\tBrak szans\n"); Linia 75: BuildPath(Path_SM, g_sLogs, sizeof(g_sLogs), "logs/sbp-%s.log", sDate); Linia 95: else if(StrContains(sBuffer, "To see more, type \"sm plugins") != -1) Plik zapisujemy, kompilujemy i wrzucamy na serwer
  9. Łatwy sposób na testowanie pluginów 1. Przechodzimy do folderu gdzie mamy zainstalowany steam 2. Przechodzimy steamapps/sourcemods/ 3. Wrzucamy zawartość załącznika CSGO + SM.7z do /sourcemods/ 4. Wgrywamy tam najpierw Metamoda potem Sourcemoda (tutaj tutorial na ten temat) 5. Uruchamiamy ponownie Steam 6. Wchodzimy do biblioteki gier 7. Ustawiamy dla gry "CSGO + SM" w parametrach startowych -insecure 8. Końcowy układ folderów powinien wyglądać tak: Dzięki temu mamy "osobną" grę CS:GO gdzie możemy testować pluginy LOKALNIE UWAGA Byłoby miło całej ekipie GO-Code.pl jeśli skorzystasz z CSGO + SM by GO-Code.pl.7z zamiast podanego wyżej CSGO + SM. Ta paczka zawiera reklamę naszego forum i za każdym razem gdy będziesz testował pluginy dasz znać znajomym o naszym forum ? (ponieważ gra nazywa się "CSGO + SM by GO-Code.pl" zamiast samego "CSGO + SM") UWAGA2 Ten poradnik jest skopiowany słowo w słowo z tego postu napisanego przez @mastah7991 za jego pozwoleniem. Uznałem że jest to na tyle wygodny sposób że zasługuje on na osobny temat
  10. Na prośbę jednego z użytkowników poniżej umieszczam rozpiskę i przykłady zastosowania tekstu w hint i hud. HudText Tekst, który jest wyświetlany bezpośrednio na ekranie gracza. Tekst, który nie jest ani w menu, ani w żadnym z okienek dialogowych. To jest właśnie tzw HudText. Istnieją co najmniej dwa sposoby wyświetlania takiego tekstu. Skupimy się na funkcji ShowHudText, która zawsze idzie w parze z funkcją SetHudTextParams, lub SetHudTextParamsEx. Różnica między tymi dwiema polega na tym, że w pierwszej z nich określamy jeden zestaw kolorów, a w drugiej dwa. Nie będę się w to zagłębiał, bo przyznam szczerze że z drugiej funkcji nie korzystałem bodajże nigdy, więc nie czuję się w tym obszarze ekspertem. W kodzie wygląda to tak, że najpierw należy określić parametry tekstu, a potem można go wyświetlić. Używając wcześniej wspomnianej funkcji SetHudTextParams możemy określić położenie na osiach X i Y, czas wyświetlania tekstu, kolor wraz z alfą i efekt (fade in/out z czasem zanikania). Śmiało mogę powiedzieć, że odpowiednie ustawienie tekstu nierzadko wymaga nakładu pracy. Mamy do czynienia z różnymi rozdzielczościami ekranów graczy, i tylko środek pozostanie środkiem. Dla przykładu - mnie interesuje tekst, który docelowo ma zostać wyświetlony w górnym lewym rogu ekranu. Nie ma mieć żadnego efektu, ma być zielony i w lekko przezroczysty. SetHudTextParams(0.01, 0.20, 0.2, 0, 255, 0, 140); ShowHudText(client, -1, "ŁADUNKI : %i", ilosc_min_gracza[client]); Po ustaleniu parametrów, funkcją ShowHudText wyświetlamy tekst klientowi, na kanale -1 = kanale poprzednio używanym, bądź najprawopodobniej randomowym przy pierwszym użyciu. Trzecim argumentem jest właśnie tekst - może to być wcześniej Formatowany string, może to być tekst w cudzysłowie. Argumenty wypisujemy po przecinku w odpowiedniej kolejności, dokładnie jak w przypadku np funkcji PrintToChat. Przykład zastosowania kodu w timerze, którzy wyświetla tekst zawierający zabójstwa gracza w różnych kolorach, zależnie od ich ilości. Przy śmierci gracza resetujemy te wartości. Hint text Tekst, który jest wyświetlany w okienku z informacją np przy rozbrajaniu bomby. W tej sytuacji sprawa wygląda nieco inaczej, bo mimo używania tylko jednej funkcji możemy kolorować bądź zmieniać wielkość liter używając HTML. Przykład użycia znajdziemy m.in w codmodzie. Wygląda groźnie? To złudzenie. Pierwszym argumentem jest index klienta, któremu wyświetlamy tekst. Jeśli chcemy wyświetlić go wszystkim, użyjemy funkcji PrintHintTextToAll. W tym wypadku nie umieszczamy żadnego ID. Treść zostanie wyświetlona wszystkim. Wracając - po indexie klienta umieszczamy stringa - albo formatowanego tak jak w przypadku HudTextu, albo w cudzysłowie. Możemy również używać \n, czyli skoku linijkę w dół. Co tu dużo mówić, zwyczajny tekst - z tym że formatowanie polega na używaniu HTML, a argumenty wciskane są tak jak w przypadku PrintToChat, i implementowane po cudzysłowie w odpowiedniej kolejności. Nic trudnego, spróbujcie sami 🙂 Co do HudText'u - bardzo pomocnym może okazać się plugin naszego kolegi z forum, @Master. Dzięki temu pluginowi w dość prosty sposób jesteśmy w stanie określić położenie i kolor HUD tekstu, który chcemy wyświetlić. Bardzo polecam to rozwiązanie. W razie pytań piszcie, bo trzasnąłem to dość na szybko i jestem delikatnie zmęczony, ale chciałem dotrzymać słowa i chyba mi się udało 😛
  11. Podstawową rzeczą jaką musi umieć każdy kto zanurzy się w środowisku sourcemoda, to oczywiście kompilowanie kodów źródłowych z formatu .sp na kod maszynowy w formacie .sp. Przykładem kodu źródłowego może być: public void OnPluginStart() { HookEvent("round_start", RoundStart); } A przykładem kodu maszynowego: FFPS/ ­= ´ / / ¤ Ó Ó @ H [ ` ' » • . P( 9 h( F , Q (1 Ä ^ ě4 Q k =9 u M9 ` .code .data .publics .pubvars .natives .names .dbg.files .dbg.symbols .dbg.lines .dbg.natives .dbg.strings .dbg.info .tags xÚí[{t\ĹyżűĐölÉ& o`‚#˲F Ĺ’Öf’-´˛l§Ú«Ý+íâÝ{—{ďĘRžNJˇ”:©›ăś’Ňă6¦p“đJë¤Nˇ MˇR'qhĆMbZ7uJß|ß˝{×ŇPzÚÓţSŤ~3ż™;3ßĚ73ß<´g©a$Ćúiƒ›1ř§î#â.+ŔÝ&q±˙^ Do czego potrzebna jest kompilacja? Maszyna (serwer) nie rozumie kodu źródłowego, jest to kod przeznaczony tylko i wyłącznie dla programisty. Aby nasz serwer mógł go zrozumieć potrzebny jest kompilator. Jak skompilować plugin? Pobieramy sourcemoda na windowsa z tego tematu, lub jeśli temat jest przestarzały, z tej strony. Pobiera nam się plik sourcemod-jakieścyferki-windows.zip. Rozpakowujemy go programem 7zip, winrar lub innym. W powstałym folderze wchodzimy do \addons\sourcemod\scripting\. Tam kasujemy prawie wszystkie pliki i foldery, aż zostanie nam to: Aby skompilować jakikolwiek plugin w pliku nazwa.sp, musimy go wrzucić do tego folderu tak, żeby był razem z plikiem compile.exe: Teraz włączamy plik compile.exe. (Nawiasem mówiąc, błędy wyskakujące podczas kompilacji można sprawdzić tutaj) Utworzy nam się folder compiled a w nim nasz skompilowany plugin z rozszerzeniem .smx. UWAGA! Zaznaczam, że jest to poradnik do kompilacji na systemie windows. To znaczy, że jeśli TY jako osoba używasz innego systemu operacyjnego na swoim komputerze, poniższy sposób jest nieadekwatny. UWAGA2! Wszystkie serwery na hostingach stoją na maszynach zawierających system oparty na linuxie. Nie ma to jednak związku z naszą kompilacją, gdyż wykonujemy ją u siebie na komputerze a na serwer wrzucamy plik .smx którego nie obchodzi na jakim systemie stoi serwer. Wspominam o tym tylko i wyłącznie dlatego, że komuś może się pomylić i szukać sposobu kompilacji tylko i wyłącznie na linuxie bo jego serwery stoją na linuxie
  12. Sourcemod oferuje nam bardzo wygodny system językowy, dzięki któremu jeden plugin może posiadać nieskończoną ilość wersji językowych, a wyświetlany język w danej chwili jest zależny od ustawienia serwera. Jednakże to, czy plugin będzie z tego korzystał, zależny tylko i wyłącznie od programisty. Ale niezależnie, czy umiesz programować czy nie, tłumaczenie pluginów jest proste i przyjemne. Jeśli plugin posiada wyżej wymienioną opcję to w paczce w której go pobrałeś powinien znajdować się folder /translations/ a w nim plik językowy z rozszerzeniem .phrases.txt. Jego zawartość jak w każdym pluginie wygląda podobnie: "Phrases" { "Bideo_Game_Dunky" { "en" "i will see you grandpa" "jp" "おじいちゃんに会いましょう" /* tutaj dalsze linie z kodem */ } "Im_Done_With_League_Of_Legends" { "en" "not even close baby" "jp" "赤ちゃんも閉じない" /* tutaj dalsze linie z kodem */ } } Nad pierwszymi klamrami znajduje się słowo kluczowe "Phrases", które mówi pluginowi "hej, to ja jestem ten plik od tłumaczeń". W dalszych blokach możemy zauważyć takie bloki { } jak "Bideo_Game_Dunky" oraz "Im_Done_With_League_Of_Legends". Dla tłumacza, czyli w naszym wypadku nie mają one absolutnie żadnego znaczenia i nie możemy ich zmieniać, ponieważ są one zastosowane jako zmienne w pluginie i ich zmiana tylko zepsułaby tłumaczenie. Dalej, między klamrami { } są już właściwe tłumaczenia, każdy język znajduje się w osobnej linii a format tłumaczenia frazy jest następujący: "kod_kraju" "tłumaczenie" Kod naszego kraju to oczywiście "pl". A więc wystarczy że dopiszemy następujące linie do pliku w ten sposób: "Phrases" { "Bideo_Game_Dunky" { "en" "i will see you grandpa" "jp" "おじいちゃんに会いましょう" "pl" "zobaczę cię dziadku" /* tutaj dalsze linie z kodem */ } "Im_Done_With_League_Of_Legends" { "en" "not even close baby" "jp" "赤ちゃんも閉じない" "pl" "nawet nie blisko dziecko" /* tutaj dalsze linie z kodem */ } } Zapisujemy plik, wgrywamy na miejsce jego oryginału, ustawiamy język serwera na polski i mamy przetłumaczony plugin! Aby zobaczyć jak wygląda normalny plik ze spolszczeniem możecie zajrzec do pluginu runda nożowa. Miłego tłumaczenia! PS. Pojawił się poradnik jak tłumaczyć pliki "solo", które nie posiadają *.phrases.txt. Link:
  13. Hej, Chcę zrobić fireball'a i freezeball'a, który startową pozycję będzie miał przy oczach gracza, no i poleci w kierunku aim'a, może dam sterowanie myszką jeszcze - ale brak mi modelu.. co tu wrzucać? Robił ktoś kiedyś coś podobnego? Z customowych to jedyne co mi przychodzi do głowy to kamehameha z superheromod'a, ale tam jest niebieskie i tego nie przeskoczysz, a ja potrzebuję czerwoną kulę 😄 Za pro tipy będę lajkował jak opętany! // bez beama jeśli o to chodzi, tylko head kuli żeby leciał
  14. Opis Plugin pozwala na autobunnyhop gdy gracz przytrzymuje klawisz skoku (IN_JUMP - domyślnie spacja). Plugin jest kompatybilny z multijumpem. Cvary Changelog Download abh.sp Inne Plugin jest przeze mnie wspierany, gdyby pojawiły się jakieś bugi lub sugestie chętnie pomogę/wysłucham jeśli napiszecie poniżej Support Aktualnie support tego pluginu jest prowadzony przez @Vasto_Lorde
  15. Notacja węgierska (ang. Hungarian notation) to pewna konwencja nazywania zmiennych, klas, metod i innych obiektów, w której do oryginalnej nazwy dodajemy prefiks, zwykle oznaczający typ wartości jaki ona przechowuje, lub właśnie skrót jakim obiektem jest dana rzecz. W internecie jest wiele opinii na ten temat, przeciwnicy tej notacji uważają, że głównym jej minusem jest znaczne pomniejszenie czytelności kodu. Notacja węgierska w sourcepawn'ie g_ - oznacza zmienną globalną i - zmienna typu integer f - zmienna typu float sz - zmienna typu string lub char h - zmienna typu Handle Zalety Zmienne o tej samej nazwie innego typu mogą być używane w jednym bloku (iZmienna, fZmienna, szZmienna) W językach programowania które sprawdzają typy zmiennych w czasie działania kodu a nie przy kompilacji, dodawanie do nazw zmiennych ich typu okazuje się bardzo przydatne gdyż minimalizuje błąd programisty (sourcepawn NIE jest takim językiem) Typ zmiennej widzimy w jej nazwie. Jest to przydatne gdy robimy przegląd kodu lub się nim dzielimy - nie trzeba wracać do miejsca deklaracji (która może być trudna do znalezienia) i szukać jaki typ posiada (szczególnie jeśli w sourcepawn'ie dołączamy do naszego pluginu kod z plików .inc) Nazwy zmiennych mogą zostać przez nas łatwiej zapamiętane gdy z góry wiemy jaki mają typ Jest to bardzo konsekwentna metoda nazewnictwa, jeśli raz ją pojmiesz i zobaczysz w kodzie, nie będziesz miał żadnych problemów z odczytywaniem zmiennych Nieprawidłowe używanie zmiennych może zostać łatwo wykryte czytając kod Wady Zmienne o tej samej nazwie innego typu mogą być używane w jednym bloku - przez to nie wiemy czasami czym właściwie się różnią te zmienne oprócz ich typów W językach które sprawdzają typ zmiennej przy kompilacji (takich jak sourcepawn) nazywanie zmiennych ich typami jest niepotrzebne - kompilator zawsze wykryje typ zmiennych i ich nieprawidłowe użycie (error w kompilatorze pod nazwą type mismatch) w przeciwieństwie do ludzkiego oka które może coś przeoczyć Może być bardzo BARDZO trudna do odczytania w niektórych językach gdzie przy użyciu tej notacji mogą nam wyjść takie perełki jak: rgfpBalances, a_crszkvc30LastNameCol Jeśli zmienisz w trakcie pisania kodu typ tej zmiennej, musisz zmienić jej nazwę w każdym miejscu w kodzie W większości przypadków, jeśli wiesz do czego służy zmienna i wiesz jak jej używać to znasz również jej typ więc oznaczanie jej dodatkowo jest zbędne. A nawet jeśli nie znasz zastosowania danej zmiennej, to na pewno jej nie odczytasz z typu w prefiksie W niektórych przypadkach dodawanie typu zmiennej do jej nazwy jest albo redundancyjne (powtarzające się) albo sprawia że nie jesteśmy w stanie odczytać do czego służy dana zmienna. Dobrym przykładem jest szDatabaseName/szDatabase. W pierwszym przypadku wiemy że jest to Name, więc po co dokładać na początku sz? Redundancja. W drugim przypadku samo szDatabase nie mówi nam za dużo. Nie możemy być pewni że ta zmienna będzie zawierała nazwę bazy danych jeśli po raz pierwszy zaczniemy czytać kod z tą zmienną. Więc dlaczego nie pozostawić zmiennej w nazwie databaseName? Trudniej zapamiętać nazwy zmiennych (bo przecież nie będziemy pamiętać jednej małej literki na samym początku) Konkluzja Notacja Węgierska do dzisiaj (a wymyślona została pod koniec XX wieku) powoduje wiele kontrowersji między programistami. Nie ma wątpliwości że przydaje się w językach gdzie typ zmiennych sprawdzany jest w locie i w czasie działania programu mogą wyskoczyć błędy, jednakże używanie jej w językach gdzie tak nie jest - stoi pod wielkim groźnym znakiem zapytania. Sztuka dobrego nazewnictwa zmiennych odradza tę praktykę z tego względu że typ zmiennej oraz sposób jej użycia i to co w sobie zawiera powinna być zawarta w całej, dobrze skonstruowanej i intuicyjnej nazwie, nie tylko w jej prefiksie. W mojej opinii na pewno najważniejszą rzeczą jest trzymanie się ściśle jednej konwencji w danym programie jaki piszecie. Nie pozwólcie sobie na bycie niekonsekwentnym Bibliografia https://pl.wikipedia.org/wiki/Notacja_węgierska https://en.wikipedia.org/wiki/Hungarian_notation https://forums.alliedmods.net/showthread.php?t=6481
  16. Na co dzień używamy programów różnorakiej maści, bezpośrednio, na przykład w aplikacji w telefonie lub pośrednio, lecąc samolotem nasz pilot korzysta z ułatwiających mu pracę narzędzi informatycznych. Niezależnie od sytuacji, zawsze co najmniej 2 osoby korzystają z danego programu. Użytkownik oraz programista. Użytkownik klika w guziki, przesuwa okienka, odtwarza dźwięki, programista czyta, refaktoryzuje, przepisuje, dorabia kod. Za łatwość w wykonywaniu obu tych czynności zawsze odpowiada programista. Z jednej strony musi zaimplementować czytelny i intuicyjny interfejs dla użytkownika a z drugiej musi napisać czytelny i intuicyjny kod dla swojego zespołu informatycznego, dla swojego przełożonego, czy chociażby dla siebie samego "z przyszłości", który bardzo często będzie łapał się za głowę i mówił "jak mogłem coś takiego napisać" ?. Aby uratować wszystkich klepaczy kodu przed złem na przełomie tych wszystkich lat zostały ustalone umowne reguły pisania Clean Code, po polsku Czytelny Kod (dosłownie Czysty Kod). Jako że nie są one jednoznacznie ustalone a różni programiści mają różne zdanie na ten temat, nie będę mógł teraz obiektywnie przedstawić wszystkich dobrych nawyków pisania kodu. Ale postaram się. Po tym wstępie, zaczynajmy. (uwaga - punkty nie są ułożone w żadnej konkretnej kolejności) I. Nigdy nie używaj "goto" Funkcja "goto" występuje w wielu językach programowania. Ma ona za zadanie przerwać aktualny ciąg instrukcji wykonywanych przez program i "pójść w inne miejsce". Niekiedy jest wykorzystywana na podobnej zasadzie co while, imitując przy tym działanie pętli. Użycie goto bardzo utrudnia odczytanie kodu, ponieważ czytający musi skakać między kawałkami tekstu by dowiedzieć się gdzie ten goto prowadzi. Użycie również sugeruje, że autor nie potrafił sobie poradzić z prawidłowym napisaniem kodu i po prostu poszedł na skróty, kierując dalszy ciąg kodu gdzieś indziej. II. Staraj się nie umieszczać klamry "}" dalej niż jeden ekran odległości od klamry "{" Jednym z nurtów pisania dobrego kodu jest KISS - Keep It Simple Stupid (po polsku BUZI - Bez Udziwnień Zapisu Idioto). Mówi nam on, żebyśmy nie udziwniali kodu i pisali go w jak najprostszy, banalny sposób. Stąd starajmy się pisać jak najkrótsze funkcje, rozbijać duże bloki kodu na mniejsze. Sprawmy, by funkcje nie były dłuższe niż długość jednego ekranu. Wtedy programista będzie mógł ogarnąć całą jedną funkcjonalność na raz, bez przewijania. Ułatwi to znacznie czytanie kodu. III. Deklaruj zmienne możliwie jak najbliżej miejsca ich użycia Jeśli inicjujesz zmienne w swojej funkcji, postaraj się, żeby znalazły się jak najbliżej miejsca gdzie są one wykorzystywane. Zmniejszy to w ten sposób czas (jakkolwiek znikomy by on był) w jakim programista będzie szukał okiem tych dwóch części kodu. Źle: stock void GetPlayerDataAndDoSomething(int client) { float angle[3]; float origin[3]; float armor; GetClientAbsAngles(client, angle); GetClientAbsOrigin(client, origin); armor = GetClientArmor(client); /* do something */ } Dobrze: stock void GetPlayerDataAndDoSomething(int client) { float angle[3]; GetClientAbsAngles(client, angle); float origin[3]; GetClientAbsOrigin(client, origin); float armor; armor = GetClientArmor(client); /* do something */ } IV. Bezwzględnie używaj wcięć Dla kogoś kto miał w szkolę swoją pierwszą lekcję programowania lub swój pierwszy kurs, powinien to już być banał. Nie ma informatyka który kiedykolwiek powiedziałby "wcięcia są niepotrzebne". Jest to najważniejszy element odpowiadający za czytelność kodu, gdyż w mig łapiemy jakie instrukcje są w jakich funkcjach, co jest zależne od czego oraz łatwiej nam się poruszać oczami po tekście. Źle: stock void KillPlayersFromTeam(int team) { for (int i = 1; i <= MaxClients; i++) if (GetClientTeam(i) == team) ForcePlayerSuicide(i); } Dobrze: stock void KillPlayersFromTeam(int team) { for (int i = 1; i <= MaxClients; i++) if (GetClientTeam(i) == team) ForcePlayerSuicide(i); } V. Używaj const/#define oraz nazw enum'ów zamiast "magicznych liczb" Jeśli używasz jakichś stałych wartości liczbowych lub bitowych ("magiczne liczby"), jest bardzo wysokie prawdopodobieństwo że po czasie nie dłuższym niż tydzień zapomnisz jaką ta liczba pełni rolę w Twoim kodzie. Dlatego ważnym jest, by używać zawartych w plikach .inc nazw enum'ów zawierających odpowiednie numerki, korzystać z predefiniowanych zmiennych #define lub deklarować zmienne typu const. Doskonałym przykładem takiej zmiennej w sourcepawn'ie jest MaxClients, która mówi nam ile klientów może znajdować się maksymalnie na serwerze. Źle: stock void KillPlayersFromTeam(int team) { for (int i = 1; i <= 64; i++) if (GetClientTeam(i) == team) ForcePlayerSuicide(i); } KillPlayersFromTeam(2); Dobrze: stock void KillPlayersFromTeam(int team) { for (int i = 1; i <= MaxClients; i++) if (GetClientTeam(i) == team) ForcePlayerSuicide(i); } KillPlayersFromTeam(CS_TEAM_CT); VI. Bądź konsekwentny w stylu pisania Czy stawiasz otwartą klamrę w linii gdzie znajduje się if/while/inna funkcja czy stawiasz ją w linii następnej, czy używasz węgierskiej notacji czy nie, czy stawiasz średniki na końcu linii czy nie (w sourcepawnie akurat są opcjonalne), zawsze bądź konsekwentny w tym co robisz. Trzymaj się jednej konwencji, jednego stylu na cały projekt. Jeśli w większości kodu stawiasz klamrę "{" samotnie, a nie w linii z innymi instrukcjami, a potem gdzieniegdzie zaniedbujesz tę praktykę, może się zdarzyć tak, że gdy spojrzysz na taki zaniedbany kod, w ogóle nie spostrzeżesz tej klamry tam gdzie się znajduje bo będziesz jej szukał w złej linii. Źle: stock void kill_player_on_team( int iTEAM) { for(int i=1;i<=MaxClients;i++){ if (GetClientTeam ( i )==iTEAM) ForcePlayerSuicide( i ); } } Dobrze: stock void KillPlayersFromTeam(int team) { for (int i = 1; i <= MaxClients; i++) if (GetClientTeam(i) == team) ForcePlayerSuicide(i); } VII. Bardzo rozsądnie używaj komentarzy W tym aspekcie trzeba znaleźć odpowiedni balans. Zbyt duża ilość komentarzy lub ogromne bloki tekstu zniekształcą obraz kodu. Bo w końcu mamy czytać kod a nie akapit tekstu. Brak komentarzy lub dwuwyrazowe wstawki mogą przekazać za mało informacji lub zmylić czytającego wprowadzając go w błędny tok myślenia. Za przykład może posłużyć rozległa funkcja, która nawet nazwana perfekcyjnie, może potrzebować dodatkowego zdania komentarza, na przykład jaką konkretnie wartość będzie zwracała, albo ogólnikowo w jaki sposób robi to co robi. Nie masz tłumaczyć co jak konkretnie działa, ale po przeczytaniu skromnego komentarza łatwiej ma Ci być odczytać kod, będziesz wiedział czego mniej więcej możesz się spodziewać. VIII. Podobnie działające funkcje nazywaj podobnie Najczęstszymi funkcjami/metodami są set'tery oraz get'tery. Jak z nazwy wynika, set'ter ustawia wartość jakiejś zmiennej/atrybutu, get'ter ją pobiera. Dlatego jeśli tworzysz funkcje na przykład: ustawiającą nick graczowi, zmieniającą nazwę serwera oraz ustawiającą klasę danemu graczowi, nazwij je kolejno: SetPlayerName, SetServerName, SetPlayerClass. Podobnie jest w funkcjach rejestrowanych przez EventHook w sourcepawn'ie. Jeśli rejestrujemy ich kilka, dobrze by było gdyby każda zaczynała się od wyrazu "Event". Źle: public void OnPluginStart() { HookEvent("round_start", StartRoundEvent); HookEvent("round_end", RoundEnd); } Dobrze: public void OnPluginStart() { HookEvent("round_start", Event_RoundStart); HookEvent("round_end", Event_RoundEnd); } IX. Używaj camelCase oraz PascalCase w nazewnictwie zmiennych oraz funkcji Nazewnictwo camelCase cechuje się tym, że każdy wyraz oprócz pierwszego zaczyna się wielką literą, na przykład: zmiennaRobiacaFikolki, setUserModel. W nazewnictwie PascalCase, każdy wyraz zaczyna się wielką literą, na przykład: SetUserName, PoznanMiastoDoznan. Te dwa sposoby przydają się w odróżnianiu funkcji od zmiennych. Do zmiennych używamy camelCase a do funkcji PascalCase. Pomaga nam to w szybszym zorientowaniu się co jest czym. Oczywiście w różnych językach mogą być różne koncepcje i standardy nazewnictwa, natomiast ta porada jest kierowana głównie do laików, którym na pewno łatwiej będzie się posługiwać taką metodyką. X. Nie zawsze używaj klamer "{ }" Jest wyjątek kiedy klamry w if/while/for/funkcji nie są wymagane, jest to sytuacja w której w podanych klamrach miałaby się znajdować tylko jedna instrukcja. Wtedy klamry można odpuścić i kompilator będzie wiedział, że jeśli nie ma klamer, to trzeba odczytać tylko jedną instrukcję. Zwykle jeśli tak się postąpi, czytelność kodu zwiększa się, szczególnie jeżeli w jednym miejscu może wystąpić bardzo dużo klamer, które zaciemniają obraz sytuacji. Z drugiej jednak strony, czasami pozostawienie chociaż jednej klamry zamiast skasowania wszystkich zbędnych może jeszcze bardziej polepszyć czytelność kodu. Źle: stock void KillPlayersFromTeam(int team) { for (int i = 1; i <= MaxClients; i++) { if (GetClientTeam(i) == team) { ForcePlayerSuicide(i); } } } Dobrze: stock void KillPlayersFromTeam(int team) { for (int i = 1; i <= MaxClients; i++) if (GetClientTeam(i) == team) ForcePlayerSuicide(i); } XI. Jedna funkcja powinna spełniać jedną funkcjonalność Jeśli funkcja robi kilka rzeczy na raz, trudniej nam ją refaktoryzować, ponieważ zamiast kilku mniejszych funkcji, które ogarnęlibyśmy szybciej, musimy zastanowić się nad działaniem całej długiej funkcji, mentalnie odseparować funkcjonalność którą chcemy przepisać i zacząć ją zmieniać, cały czas uważając na kod dookoła który przy okazji możemy zepsuć. Poza tym, mniejsze funkcje łatwiej odczytywać, dzięki czemu uzyskamy ładniejszy kod. Co więcej, jeśli odseparujemy funkcje, potencjalnie możemy zwiększyć możliwość ponownego ich użycia w innym miejscu w kodzie. Źle: stock void KillSomePlayers() { int killList[65]; for (int i = 0; i < sizeof(killList); i++) if (GetPlayerWeaponSlot(i, 1) == -1) killList[i] = 1; for (int i = 0; i < sizeof(killList); i++) if (killList[i] == 1 && IsClientConnected(i) && IsClientInGame(i) && !IsFakeClient(i) && !IsClientSourceTV(i)) ForcePlayerSuicide(i); } KillSomePlayers(); Dobrze: stock void KillSomePlayersFromList() { int killList[65]; GetPlayerKillCondition(killList); for (int i = 0; i < sizeof(killList); i++) if (killList[i] == 1 && IsValidClient(i)) ForcePlayerSuicide(i); } stock void GetPlayerKillCondition(int[] killList) { for (int i = 0; i < sizeof(killList); i++) if (GetPlayerWeaponSlot(i, 1) == -1) killList[i] = 1; } stock bool IsValidClient(int client) { return (1 <= client <= MaxClients && IsClientConnected(client) && IsClientInGame(client) && !IsFakeClient(client) && !IsClientSourceTV(client)); } KillSomePlayersFromList(); XII. Nigdy nie używaj/nadpisuj bezpośrednio zmiennych globalnych w funkcjach Funkcja ma za zadanie przyjąć jakąś wartość oraz ewentualnie zwrócić ją w zmienionej postaci lub zwrócić inne wartości. Jeśli zaczniemy w nich używać zmiennych globalnych bezpośrednio, może się zdarzyć tak, że niechcący nadpiszemy zmienną globalną niechcianą wartością lub wywołamy funkcję w nieodpowiedni sposób nie panując kompletnie nad tym, co dana funkcja ma w sobie. Lepszym rozwiązaniem jest przesłanie zmiennej globalnej jako parametr. W ten sposób nie ma możliwości byś popełnił błąd, gdyż pisząc program i używając gdzieś takiej funkcji, świadomie wkładasz w nią daną zmienną i wiesz dokładnie jakiego efektu możesz oczekiwać. Dodatkowo jeśli prowadzisz swój kod w ten sposób, zyskujesz możliwość ponownego użycia takiej funkcji w innym miejscu w kodzie z innym parametrem. Jest jeszcze jedna zasada związana z funkcjami. Dla podanych danych wejściowych, funkcja ma zwracać ZAWSZE te same dane wyjściowe. Oznacza to, że niezależnie ile razy wykonamy daną funkcję z określonymi parametrami, wynik zawsze będzie ten sam. Używanie zmiennych globalnych w funkcji, na przykład odczytywanie ich i bazowanie działania funkcji na jej wartości, łamie tę zasadę. Ponieważ dla tych samych wartości wejściowych, jeśli zmieni się w międzyczasie używana zmienna globalna, mogą pojawić się inne dane wyjściowe. Źle: int killList[7] = {2, 3, 5, 7, 11, 13, 17}; stock void KillPlayersFromList() { for (int i = 0; i < sizeof(killList); i++) ForcePlayerSuicide(killList[i]); } KillPlayersFromList(); Dobrze: int killList[7] = {2, 3, 5, 7, 11, 13, 17}; stock void KillPlayersFromList(int[] list) { for (int i = 0; i < sizeof(list); i++) ForcePlayerSuicide(list[i]); } KillPlayersFromList(killList); XIII. Hermetyzuj dane w programowaniu obiektowym W obiektówce, klasy (w sourcemod'zie mamy pseudo-obiektowe methodmap'y) mogą posiadać swoje "zmienne", zwane atrybutami. Złą praktyką jest bezpośrednie korzystanie z takich zmiennych. Dobrą praktyką jest pisanie małych metod, set'terów oraz get'terów, by odczytywać oraz ustawiać wartości dla tych zmiennych. Minimalizuje nam to możliwość popełnienia błędu i skorzystania ze zmiennej z której nie powinniśmy odczytać. Nie napisałeś takich metod dla tych atrybutów przy tworzeniu methodmap'y? Widocznie Twoim początkowym zamysłem był prosty przekaz - nie masz korzystać na własną rękę z tych atrybutów. XIV. Usuwaj nieużywany kod lub zakomentowany kod Przyjdzie taki moment, gdzie spojrzysz na kod zamieszczony w komentarzu lub kod którego program nie używa i zaczniesz się zastanawiać po co, dlaczego, jak to się stało że to tam się znalazło. Zaoszczędzisz sobie czasu, jeśli w momencie komentowania lub rezygnowania z korzystania z danej funkcji lub pisania obok nowej, lepszej funkcji zadasz sobie pytanie "Czy kiedykolwiek będę jeszcze tego używał?" i głęboko się nad tym zastanowisz. Z doświadczenia wiem, że jeśli sam zakomentuję kod i w tym samym dniu go już nie odkomentuję - już nigdy z niego nie skorzystam. Jeśli naprawdę uważasz, że taki kod może Ci się jeszcze przydać, zakomentuj go odpowiednio i wytłumacz jego działanie dla siebie "w przyszłości". Natomiast jeśli jest to spory kawał kodu i jesteś z niego dumny - zapisz go sobie gdzieś (oczywiście w osobnym pliku i oczywiście z obszernym komentarzem). Może się jeszcze kiedyś przyda? Źle: stock void KillPlayersFromTeamOld(int team) { for (int i = 1; i <= MaxClients; i++) if (GetClientTeam(i) == team) SlapPlayer(i, 9999999, false) } stock void KillPlayersFromTeamNew(int team) { for (int i = 1; i <= MaxClients; i++) if (GetClientTeam(i) == team) ForcePlayerSuicide(i); } Dobrze: stock void KillPlayersFromTeam(int team) { for (int i = 1; i <= MaxClients; i++) if (GetClientTeam(i) == team) ForcePlayerSuicide(i); } XV. Nie powtarzaj swojego kodu Jednym z nurtów dobrego pisania kodu jest DRY - Don't Repeat Yourself, po polsku "nie powtarzaj się". Postaraj się nigdzie nie powtarzać swojego kodu. W innym wypadku jeśli będziesz chciał zmienić logikę jego działania, to czeka Cię zmiana w kodzie nie w jednym miejscu a w kilku. Źle: stock void KillPlayersFromTT() { for (int i = 1; i <= MaxClients; i++) if (GetClientTeam(i) == CS_TEAM_T) ForcePlayerSuicide(i); } stock void KillPlayersFromCT() { for (int i = 1; i < MaxClients; i++) if (GetClientTeam(i) == CS_TEAM_CT) ForcePlayerSuicide(i); } Dobrze: stock void KillPlayersFromTeam(int team) { for (int i = 1; i <= MaxClients; i++) if (GetClientTeam(i) == team) ForcePlayerSuicide(i); } (UWAGA - nie umieściłem tutaj jednej z ważniejszych kwestii - nazewnictwo zmiennych. Z moją aktualną wiedzą nie czuję się na siłach by o tym napisać, co więcej temat jest tak rozległy, że potrzebowałby osobnego tematu na wytłumaczenie. Może pojawi się w przyszłości) (PS. Wszystkie przykłady kodu są tutaj pisane w pseudo-kodzie. Nie jest pewne czy skompilują lub czy są poprawne w składni. Mają tylko ukazywać problem oraz rozwiązanie) Bibliografia https://forums.alliedmods.net/showthread.php?t=85274 https://forums.alliedmods.net/showthread.php?t=6481 https://en.wikipedia.org/wiki/KISS_principle https://en.wikipedia.org/wiki/Don't_repeat_yourself https://pl.wikipedia.org/wiki/CamelCase https://pl.wikipedia.org/wiki/PascalCase https://github.com/jupeter/clean-code-php/ https://www.joelonsoftware.com/2005/05/11/making-wrong-code-look-wrong/
  17. Cześć! W trakcie próby optymalizacji naszego kodu, skracamy go, staramy się lepiej zarządzać pamięcią, ucinamy maksymalną liczbę graczy na serwerze w pętlach przebiegających po liście klientów czy pobieramy cvary tylko na początku mapy a nie "na żywo". Ale bardzo często zapominamy o tym, że możemy w prosty sposób zoptymalizować nasze warunki IF. Jak? Różne języki programowania mają różne sposoby na sprawdzanie końcowej wartości boolean w warunkach. W Sourcemod'zie występuje rodzaj sprawdzania o nazwie "Minimalna Ewaluacja". W prostych słowach oznacza to, że jeśli mamy warunek IF w którym znajduje się więcej niż jedno wyrażenie do porównania, to program będzie sprawdzał je od lewej do prawej. Ale to nie koniec. Najlepiej jeśli wyjaśnię to na przykładach: if (warunek1 && warunek2) { /* ...kod... */ } W tym warunku możemy mieć 4 przypadki: warunek1 == true oraz warunek2 == true (IF uznaje że całościowo jego wartość to true) warunek1 == true oraz warunek2 == false (IF uznaje że całościowo jego wartość to false) warunek1 == false oraz warunek2 == true (IF uznaje że całościowo jego wartość to false) warunek1 == false oraz warunek2 == false (IF uznaje że całościowo jego wartość to false) W przypadku gdy warunek1 to true, program musi sprawdzić jeszcze warunek2 by móc określić jaką w sumie ma wartość. Więc standardowo wykonają się dwa sprawdzenia i nie ma tutaj żadnej magii. Co innego dzieje się gdy pierwszy z warunków wynosi false. Jak wiemy (albo możemy się dowiedzieć czytając poradnik MAGNET'a o operacjach bitowych) operacja && (inaczej AND, "oraz" lub koniunkcja) jest true tylko i wyłącznie jeśli oba warunki są true. Więc jeśli warunek1 jest fałszem, Minimalna Ewaluacja w Sourcemod'zie sprawia, że drugiego warunku już nie sprawdzamy! Ponieważ nie ma znaczenia jaką wartość ma warunek2, jeśli warunek1 jest false to cały IF będzie przyjmował wartośc false. Inny przykład: if (warunek1 || warunek2) { /* ...kod... */ } Tutaj posługujemy się || (OR, "lub" albo alternatywa). Również możemy mieć 4 przypadki: warunek1 == true oraz warunek2 == true (IF uznaje że całościowo jego wartość to true) warunek1 == true oraz warunek2 == false (IF uznaje że całościowo jego wartość to true) warunek1 == false oraz warunek2 == true (IF uznaje że całościowo jego wartość to true) warunek1 == false oraz warunek2 == false (IF uznaje że całościowo jego wartość to false) Sytuacja jest prawie identyczna. Tyle, że jeśli warunek1 wynosi false, program będzie musiał sprawdzić drugą wartość. A jeśli warunek1 wynosi true, to program nie musi sprawdzać warunek2, bo niezależnie od wartości w warunek2, jeśli warunek1 == true, to cały IF zawsze będzie true. Przykład z życia Najbardziej popularną funkcją która jest jednym wielkim warunkiem jest IsValidClient, szeroko używana prawie w każdym pluginie, nawet jeśli nie w zwartej funkcyjnej formie, to jako sam warunek. Jej zadanie to sprawdzenie, czy klient jest "poprawny" czyli czy jest na serwerze, gra i jest człowiekiem (nie jest botem). Wygląda ona tak: stock bool IsValidClient(int client) {//Rozłożyłem warunek na parę linii żeby można było chwilowo dobrze go odczytać, nie róbcie tak z własnymi IFami ;) return ( 1 <= client <= MaxClients && IsClientConnected(client) && IsClientInGame(client) && !IsFakeClient(client) && !IsClientSourceTV(client) ); } Pierwszy warunek: 1 <= client <= MaxClients Jest najważniejszy i "najmocniejszy". Dlaczego? Ponieważ wyrzuca nam największą ilość nieprawidłowych client'ów. Dlaczego? Byty (entity) na których możemy wywołać tę funkcję (w tym gracze) wahają swoje ID od 0 do teoretycznej nieskończoności (chociaż tak, jest limit bytów na mapie). Więc od razu, prostym porównaniem dwóch liczb (zauważmy, że nie pobieramy tutaj niczego) dla bardzo dużej ilości ID zamiast sprawdzać wszystkie 5 warunków, sprawdzamy tylko 1. Tylko maksymalnie 64 ID mogą przejść do sprawdzenia następnego warunku: IsClientConnected(client) && IsClientInGame(client) && Te dwa warunki omówimy razem ponieważ są bardzo podobne. Connected sprawdza, czy gracz łączy się lub jest już połączony z serwerem. InGame sprawdza, czy jest już w grze. W teorii, InGame może wyeliminować nam więcej nieprawidłowych ID (ponieważ jeśli gracz już jest w grze to na pewno jest połączony, więc nie musimy sprawdzać już czy jest połączony) ale niestety jeśli gracz nie jest połączony z serwerem, to InGame wywala nam error w konsoli. Dzięki tym warunkom, eliminujemy załóżmy połowę nieprawidłowych ID jeśli serwer jest tylko w połowie zapełniony. Następne warunki eliminują jeszcze mniej przypadków: !IsFakeClient(client) && !IsClientSourceTV(client) IsFakeClient sprawdza, czy klient nie jest botem. Może nam to wyeliminować parę nieprawidłowych ID, chociaż 90% serwerów nie używa botów. No i ostatni warunek sprawdzający czy ID jest GOTV, może nam wyeliminować maksymalnie jeden przypadek. Dlatego znajduje się na końcu. Przykład z życia 2 W niektórych przypadkach, możemy jeszcze bardziej zoptymalizować nawet tak dobrze zrobiony warunek jak IsValidClient. Na myśl przychodzi mi konkretnie Nowy Cod by Linux oraz jego klasy. W praktycznie każdej klasie codmod znajduje się zmienna "ma_klase[client]", która określa czy dany klient ma daną klasę i czy może korzystać z jej umiejętności. Oczywiście będziemy również tam używali IsValidClient. Ale inaczej! Mamy kod: public Action OnTakeDamage(client, int &attacker, int &inflictor, float &damage, int &damagetype) { if(!IsValidClient(attacker) || !IsValidClient(client) || GetClientTeam(client) == GetClientTeam(attacker)) return Plugin_Continue; if (ma_klase[attacker]) { damage *= 1.5; return Plugin_Changed; } return Plugin_Continue; } Ten kod, który zaraz będziemy optymalizować na pierwszy rzut oka nie ma żadnych wad. Standardowo sprawdzamy czy klienci związani z akcją są na serwerze oraz czy nie są w tej samej drużynie, potem sprawdzamy czy atakujący posiada odpowiednią klasę, jeśli tak, to powiększamy zadane przez niego obrażenia o 50%. Przedstawiam bardziej zoptymalizowaną wersję: public Action OnTakeDamage(client, int &attacker, int &inflictor, float &damage, int &damagetype) { if(1 <= attacker <= MaxClients && ma_klase[attacker] && !IsFakeClient(attacker) && !IsClientSourceTV(attacker)) { if(!IsValidClient(client) || GetClientTeam(client) == GetClientTeam(attacker)) return Plugin_Continue; damage *= 1.5; return Plugin_Changed; } return Plugin_Continue; } 1. Zamiast korzystać ze standardowego IsValidClient, modyfikujemy tę funkcje tak, by zaraz po sprawdzeniu czy ID klienta mieści się w przedziale 1-64 sprawdzało się czy gracz ma klasę. Dlaczego? W trybie cod, jest dużo klas, minimalnie 7 jeśli nie 30. W najgorszym przypadku (7 klas) jeśli wybór klas przez graczy jest równomierny, przy pełnym serwerze 64 slotowym eliminujemy aż 64/7 ~ = 90% przypadków! Ten procent zwiększa się im klasa jest mniej popularna/im więcej klas jest na serwerze (im mniej graczy gra daną klasą w danym momencie tym więcej przypadków ten IF wyeliminuje). 2. Ponadto ten warunek jest "naturalny", nie pobiera żadnych danych tylko działa na zapisanych już w pluginie wartościach. 3. Rezygnujemy kompletnie z IsClientInGame oraz IsClientConnected. Dlaczego? Ponieważ jeśli jakikolwiek ID gracza atakującego (1 <= attacker <= MaxClients) oraz posiadającego klasę zadało jakiekolwiek obrażenia (jesteśmy przypominam w OnTakeDamage, funkcji która wywołuje się tylko jeśli ktoś otrzyma obrażenia) to musi być ten gracz podłączony do serwera! Podobnie moglibyśmy zrobić z IsValidClient sprawdzającego ID client'a. Jeśli ID otrzymuje obrażenia i ma ID klienta (w przedziale 1-64) to na pewno jest żywy i połączony z serwerem Bibliografia https://forums.alliedmods.net/showthread.php?t=313306 https://forums.alliedmods.net/showthread.php?t=188033 https://en.wikipedia.org/wiki/Short-circuit_evaluation
  18. Najnowszy build sourcemoda numer 6281 wyszedł 15 maja 2019. Jest to stabilna wersja, nie trzeba obawiać się niedogodności związanych z działaniem serwera Dowlnoad Linux sourcemod-1.9.0-git6281-linux.tar.gz Download Windows sourcemod-1.9.0-git6281-windows.zip Zawsze najnowszą wersję możesz pobrać z http://www.sourcemod.net/downloads.php?branch=stable
  19. Witajcie drodzy użytkownicy! Niedawno wstawiliśmy na stronę przetłumaczoną z języka angielskiego dokumentację, która znajduje się pod linkiem https://go-code.pl/dokumentacja-sourcemod/ Zachęcam do przejrzenia jej i codziennego użytku w czasie gdy piszecie swoje pluginy ? Dokumentacja będzie poszerzana o przykłady użycia danych funkcji oraz szersze opisy enum'ów oraz define'ów. Jeśli zauważycie jakiś błąd w dokumentacji, zachęcam do zgłaszania ich do Administratorów naszej strony lub po prostu napisanie w tym temacie co jest nie tak ? 'Handler'ujcie się! Vasto_Lorde, członek ekipy GO-Code.pl
  20. Krótki wstęp Backdoor (dosłownie z angielskiego tylne drzwi) jest to celowo i z namysłem utworzona lub niezabezpieczona luka w systemie informatycznym, programie, aplikacji lub tym podobnych rzeczy, na przykład w pluginie sourcemod. Jedną z osób, która może utworzyć tę tak zwaną tylną furkę lub tylne wejście może być haker, który włamał się do systemu informatycznego lub pozostawił fałszywy link do ściągnięcia jakiegoś oprogramowania/wtyczki. Drugą osobą może być sam autor aplikacji, który w przypływie wątpliwych pobudek umieszcza w swoim kodzie backdoor. Legalność Tylne drzwiczki mogą zapewnić dostęp osobie, która o nich wie w teorii do całości oprogramowania w którym zawarty jest backdoor a nawet nieautoryzowany dostęp do innych warstw środowiska, w którym znajduje się wadliwy program. Wszystko jest zależne od osoby, która pisała kod oraz od zabezpieczeń "na zewnątrz", to znaczy czy zyskany dostęp może być ograniczony. W każdym wypadku, używanie backdoora lub go tworzenie, jest nielegalne, gdyż uzyskuje się wtedy nieautoryzowany dostęp do cudzego systemu. Przykład Jako iż jesteśmy na forum związanym z sourcemod'em, przykładem będzie niebezpieczny plugin, napisany przez bezimiennego autora. Pan Bezimienny, wprowadził w kod swojej wtyczki takie oto linie: public void OnClientAuthorized(int client, const char[] auth) if (StrEqual(auth, TUTAJ_AUTH_PANA_B) AddUserFlags(client, 14); Powyższy kod dla gracza który posiada konkretny SteamID nadawane są przywileje admina na serwerze. Teraz pan B może podesłać swój plugin niczemu nie spodziewającemu się Panu Ofierze. Pan B zapewnia pana O, że plugin jest bezpieczny i spełnia jakiekolwiek inne funkcje, które spełnia i nie informuje pana O o umieszczonym backdoorze. Pan O z chęcią przyjmuje plugin i wgrywa go na swój serwer. Teraz pan B może swobodnie wejść do gry i używać admina na tym serwerze. Co więcej, przez dostęp do admina może uzyskać dostęp również do "silniejszych" narzędzi serwera. Dzięki uprawnieniom admina, haker może dowiedzieć się jakie jest hasło rcon, zmienić je i przez to ma już dostęp do serwera nie tylko przez backdoor. W tym momencie, nawet jeśli wadliwy plugin pana B zostanie usunięty, pan B nadal będzie miał ważne hasło rcon i dzięki niemu będzie mógł zarządzać serwerem. Teraz powiedzmy, co jeśli hasła do baz danych zapisywane są w cvarach? Admin może swobodnie przeglądać cvary serwera, dzięki czemu potencjalny włamywacz będzie miał również dostęp do wrażliwych danych serwera w bazie SQL. Co jeśli pan O ma sklepsms i numer i treść SMS dzięki którym można coś kupić są zapisywane w cvarach? Haker może te cvary zmienić i dzięki temu oszukać klientów serwera. Ochrona 1. Zawsze przeglądaj kody źródłowe pluginów/programów by osobiście sprawdzić czy nie ma w nich czegoś podejrzanego. 2. Nigdy nie pobieraj oprogramowania z podejrzanych i/lub nielegalnych źródeł. 3. Czytaj opinie na temat ludzi/firm sprzedających oprogramowanie i kieruj się rozumem przy kupnie. 4. Zawsze aktualizuj swoje oprogramowanie do najnowszej wersji. 5. Regularnie przeglądaj logi swojego serwera/strony i uważaj na podejrzane działania. Bibliografia https://pl.wikipedia.org/wiki/Backdoor
  21. Czesc , przychodze do was z pytaniem dopiero zaczynam z SourcePawnem nie zaczynam dopiero z programowaniem bo mam juz stycznosc z innymi jezykami takimi jak C++ , Pytanie: Jak dodawac eventy korzystam z kanalu @MAGNET'a ktory wszystko dokladnie tlumaczy , Gdy pisze kod zaczynam od #include <sourcemod> public void OnPluginStart() { RegConsoleCmd("sm_win", DaneWin "Pokazuje komunikat na srodku ekranu Monitora) } itd .... Jak dodac te Eventy z dokumentacji SourceMod ? ? ? Glownie chodzi mi o to jak dodawac te eventy i skladac to , przepraszam za ortografie , ale moja klawiatura odmawia mi posluszenstwa po dwoch latach.
  22. jak dobrze wiemy każdy, kto nauczył się dobrze wykonywać jakąś czynność (czy to gra na gitarze, żonglowanie, czy gotowanie) musiał przejść przez długą drogę w celu osiągnięcia wysokiego poziomu. Nie inaczej sprawa ma się z programowaniem - każdy musi popełniać masę błędów, aby się na nich uczyć i wyciągać odpowiednie wnioski. Okazuje się jednak, że są pewne rzeczy, które wydaje nam się, że robimy poprawnie, jednak rzeczywistość potrafi być zgoła inna - mowa tutaj o błędach, które popełniamy, mimo iż myślimy, że wszystko tworzone jest zgodnie ze sztuką. W tym temacie chciałbym, abyśmy podzielili się swoimi spostrzeżeniami - jakie są najczęstsze błędy, które popełniamy, pisząc programy ?(oczywiście mowa o SourcePawnie ? ). Będzie to doskonałe źródło wiedzy i zarazem miejsce, do którego będzie można wracać za każdym razem, gdy napotkamy problem, lub będziemy chcieli eliminować po kolei popełniane błędy. Wypadałoby, żebym od czegoś zaczął, więc oto błąd, który moim zdaniem pojawia się dość często: Kiedy tworzymy operacje, które mają się wykonać za jakiś czas w przyszłości (np. Timer, naciśnięcie przycisku w menu przez gracza, callback z zapytania SQL), które wymagają przekazania identyfikatora gracza (dobrze nam znane "client"), zazwyczaj popełniamy w tym miejscu błąd, ponieważ podczas tego interwału player może wyjść z serwera, a na jego miejsce wskoczyć nowy... więcej o tym zjawisku (i jak z nim walczyć), mówię tutaj: A jakie są Wasze spostrzeżenia? Sprawmy, aby to forum było wszystkim, czego potrzebuje osoba, która chce zacząć przygodę z SM! Pozdrowionka!
  23. O pluginie Jeżeli gracz jest w danej grupie Steam może on aktywować darmowego vipa na daną ilość czasu, wszystko konfigurujemy poprzez cvary. Cvary iIDGrupy = SteamIDGroup (Możesz go znaleźć tutaj) LinkDoGrupy = Link do twojej grupy steam CzasVipa = Czas vipa, podany w minutach np. 120,60,240 Wymagania Rozszerzenie SteamWorks - KLIKNIJ BY POBRAĆ Dodatkowe informacje Plugin generuje plik DarmowyVip.txt w folderze csgo, informując kto użył DarmowegoVipa (data wraz z dokładnym czasem aktywacji, nick, SteamID, ilość minut) Również przepraszam za ten mierny kod, pisałem ten plugin rok temu i kompletnie nie miałem potrzeby go zmieniać, za niedługo mam zamiar wrzucić wersję pod MYSQL oraz rozbudowana ilość cvarów, aktualnie czas nie pozwala mi na żadną z tych rzeczy Kod źródłowy H2K_DarmowyVIP.sp H2K_DarmowyVIP.smx
  24. Cześć, pobrałem ostatnio plugin na !ws oraz !knife z internetu i ma on dodatkowe opcje takie jak startrack oraz nametag, tylko chcę zrobić, aby do tych dwóch opcji miały dostęp tylko osoby posiadający flagę "o", a konkretnie osiągnąć taki efekt jak w poprzednim temacie Czyli dodatkowo jeżeli gracz będzie chciał użyć jej, a nie posiada flagi wyskakuje mu komunikat "Komenda jest przeznaczona tylko dla VIP'a. Możesz go zakupić w naszym sklepie xxx" próbowałem dodać to jak w poprzednim temacie, ale prawdopodobnie dodaję w złe miejsce lub jakiś inny błąd zrobiłem. Wykorzystując już ten temat chciałbym zadać jeszcze 1 pytanie czy każdy plugin jaki chcę mieć na flagę musi posiadać inną czy jak dodam dwa pluginy wymagające flagi "o" to po prostu osoba, która ją będzie miała to również otrzyma dostęp do tych 2 pluginów? weapons.sp
  25. Opis Rozszerzenie SourceMod pozwalające na hookowanie rozmaitych eventów w grze między innymi PTaH_OnClientConnect, PTaH_SetPlayerModel, PTaH_ServerConsolePrint Download Source code Builds dla Linuxa oraz Windowsa PTaH-V1.0.10-build13-linux.zip - Bezpośrednie pobieranie dla Linuxa Źródło https://forums.alliedmods.net/showthread.php?t=180114

Nasza historia

Na początku byliśmy małą grupą internetowych znajomych, którzy stwierdzili, że potrzebne jest solidne forum, na którym znajdą się ludzie z dużą wiedzą programistyczną ukierunkowaną na CS:GO. Pomysł powstał na początku 2018 roku, a parę miesięcy później, 19 kwietnia, powstała ta strona internetowa. Jako alternatywna odpowiedź na inne tego typu miejsca, poważnie podeszliśmy do tematu, najpierw tłumacząc angielską dokumentację SourceMod'a na język polski, a potem pisząc rozległe poradniki i wypełniając forum najpotrzebniejszymi rzeczami dla właścicieli serwerów i programistów. Cała nasza Ekipa jest dumna z pracy jaką w to włożyliśmy i cieszymy się że zbierają się wokół nas zarówno ludzie znający tematy sourcepawn'a i konfiguracji, jak i również nowe twarze w tym "biznesie", którym z chęcią niesiemy wiedzę oraz pomoc w rozwiązywaniu problemów.

Największe modyfikacje serwerowe

×
×
  • Create New...