Skocz do zawartości


Hej! Zauważyliśmy, że korzystasz z "adblocka".
Chcesz pozbyć się komunikatu? Wystarczy wyłączyć wtyczkę!
Jeśli chcesz swobodnie poruszać się po forum bez reklam możesz zakupić rangę "Premium".
Więcej informacji!
Dave

[Poradnik] Auto Public Channel - bot do regulacji ilości kanałów publicznych

Rekomendowane odpowiedzi

Dave

Witamy w naszym poradniku, w którym będę opisywał krok po kroku jak napisać swojego własnego bota administracyjnego.

Poradnik został napisany na prośbę użytkownika @`.Łukasz.. Dzięki za rzucenie wyzwania :)

 

Na początku zaczniemy od założeń jakie nam postawiono w wyzwaniu:

  1. Bot ma za zadanie regulować ilość kanałów w zależności od tego ile z nich jest pustych (potocznie mówiąc wolnych)
  2. Bot nie może przypadkowo wywalić użytkowników z kanałów
  3. Musi utrzymywać ustaloną w konfiguracji liczbę kanałów pustych
  4. Musi utrzymać prawidłową numerację kanałów
  5. Musi obsługiwać takie funkcje jak maksymalna ilość użytkowników (wykrywanie po kanale nadrzędnym)

 

Tak więc do dzieła! Wszystko jest szczegółowo opisane w komentarzach :)

<?php
$config =[
          "min"=>2,
          "max"=>10,
          "channel"=>[
            "unlimited"=>82,
            2=>85,
            3=>86,
            4=>87,
            5=>88
          ],
          "ilewolnych"=>2
        ];
foreach($config['channel'] as $channellmax=>$channelid){
//licznik który będzie sprawdzał ile mamy aktualnie kanałów w celu późniejszej numeracji
$countchannel = 0;
//licznik który będzie zliczał liczbę pustych kanałów
$emptychannel = 0;
//lista wszystkich kanałów ze wszystkimi parametrami
$channels = $this->channelList("-topic -flags -voice -limits -icon -secondsempty");
$channels=$channels['data']; //w innych botach widnieje specjalna funkcja pod taką operację, lecz ja sobie to po prostu uprościłem wykorzystując wbudowane właściwości języka PHP
foreach($channels as $channel)
	if($channel['pid']==$channelid){ //wybieramy kanały które należą tylko do wybranej kategorii (np. Max2)
		if($channel['total_clients']==0){ //jeśli kanał jest pusty to zwiększamy licznik pustych kanałów
			$emptychannel++;
			$lastemptychannel = $channel; //zapisujemy id ostatniego pustego kanału
    	}
		$lastchannel=$channel; //zapisujemy id ostatniego kanału
		$countchannel++; //zwiększamy licznik kanałów (później wykorzystane do numeracji kanałów)
	}
	//warunek jeśli ilość wolnych kanałów jest mniejsza niż domyślna ilość kanałów wolnych oraz nie przekracza ona maksymalnej ilości kanałów to tworzymy nowy kanał
	if (($emptychannel<$config['ilewolnych'])&&($countchannel<$config['max'])) {
		$ilekanalow=0;
		foreach($channels as $channel) if($channel['pid']==$channelid) $ilekanalow++;
		$ilekanalow++;
		if($ilekanalow<10) //jeśli kanał który sprawdzamy jest mniej niż 10-tym kanałem w danej kategorii to dopisujemy mu zero przed liczbą (ładniej wygląda)
		$ilekanalow="0".$ilekanalow;
		//Dla kanałów bez limitu ustawiamy inne parametry
		if ($channellmax=='unlimited') {
			$data['channel_name'] = " • Kanał Publiczny [ ".$ilekanalow." ]"; //nazwa kanału
			$data['channel_flag_maxclients_unlimited']=1; //kanał bez ograniczenia liczby osób
		} else {
			$data['channel_name'] = " • Kanał Publiczny [ ".$ilekanalow." ]";
			$data['channel_flag_maxclients_unlimited']=0; //kanał z ograniczeniem liczby osób
			$data['channel_maxclients']=$channellmax; //maksymalna liczba osób na kanale
		}
		$data['channel_flag_permanent']=1; //oznaczamy kanał jako permamentny
		$data['channel_codec_quality']=10; //jakość dźwięku
		$this->channelCreate($data); //tworzymy kanał z powyższymi parametrami
		$temp=$this->channelList(); //sprawdzamy ponownie listę kanałów
		$temp=$temp['data'];
		foreach($temp as $channel) {
			$lastchannellcreate=$channel['cid']; //zapisujemy id ostatnio utworzonego kanału znajdującego się w danej kategorii
			if($channel['pid']==$channelid) $order = $channel['cid'];
		}
		$this->channelMove($lastchannellcreate,$channelid,$order);//przenosimy kanał na odpowiednią pozycję w drzewie katalogów - w danej kategorii jako ostatnia pozycja, której poprzednika wskazuje nam zmienna $order
	} else if(($emptychannel>)&&($countchannel>$config['min'])) { //jeśli ilość kanałów wolnych jest większa od 2 to usuwamy kanał
		if($lastchannel['total_clients']==0) $this->channelDelete($lastchannel['cid']); //jeśli nie ma użytkowników na ostatnim kanale to go usuwamy
		else { //w przeciwnym razie przenosimy użytkowników na ostatni wolny kanał oraz kasujemy ostatni (Wcześniej zajęty) kanał
			$moveclient = $this->clientlist("-topic -flags -voice -limits -icon -secondsempty");
			foreach($moveclient['data'] as $client) {
				if ($client['cid']==$lastchannel['cid']) {
					$this->clientMove($client['clid'],$lastemptychannel['cid']);
				}
			}
		}
    }
}
}

Pewnie wielu z was się zastanawia jakim cudem to w ogóle działa :D No otóż już tłumaczę. Mi to działa, a wam nie :P Wszystkie funkcje oznaczone "$this->" są to funkcje dziedziczone od klasy nadrzędnej. W waszym przypadku nie będzie na pewno takiej zmiennej, ale za to możecie stworzyć sobie zamiast tego zwykły obiekt z klasy ts3admin.class i zastąpić te wyrażenie właśnie tym obiektem.

 

Oczywiście zanim każdy skopiuje sobie powyższy kod niech zapozna się z podstawami używania klasy ts3admin.class, a przede wszystkim z trochę rozszerzonym programowaniem w PHP (obiektowość) gdyż z racji samego faktu, iż miałem napisać tu poradnik, a nie wstawić gotowego bota nie posiada on tzw. głównego silnika (w wielu botach i innych aplikacjach nazywanego "core", co z angielskiego można tłumaczyć rdzeniem programu)

 

Powyższy kod został wyciągnięty prze ze mnie z nowej wersji ArioBota która jest aktualnie w wersji beta i jest dostępna tylko w zamkniętej grupie developerskiej.

 

Życzę powodzenia w pisaniu !!

 

PS. Proszę nie krytykować wykonania samego skryptu, z racji tego iż został on wykonany pod zupełnie innego bota, a nie spędzałem zbytnio czasu nad optymalizacją funkcji

Edytowane przez Dave

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Dave

Nie rozumiem jakie ma znaczenie w programowaniu w jakim języku piszę zmienne? 

Co do print_r to po prostu pozostałość po testach (zapomniałem ją usunąć)

Co do tego "jak mogę zrobić" to mogę to zrobić jeszcze na kilka innych sposobów, a nawet podpowiem ci że najbardziej prawidłowo powinno to wyglądać tak:

foreach($this->channelList("-topic -flags -voice -limits -icon -secondsempty")['data'] as $channel)

Wiele osób nie zrozumie całkowicie tego zapisu, dlatego też postanowiłem go po prostu rozbić na kilka części i nie zaciągać do tego nie opisanych funkcji z niektórych botów. Mój bot nie posiada takiej funkcji, ponieważ jest ona zbędna. Z resztą to widać jak najbardziej na tym przykładowym kodzie co teraz napisałem. Tak więc odpowiedz sobie na pytanie: Przyszedłeś tu szukać gotowego kodu? Czy dowiedzieć się jak go napisać?

 

Kolejna sprawa to jeśli sugerujesz jakiś kod to używaj do tego odpowiednich znaczników.

 

Dla nie wtajemniczonych funkcja getElement:

function getElement($element, $array) {
	return $array[$element];
}

Jeśli chcesz mieć gotowego takiego bota to zapłać komuś, albo sobie sam go napisz. Ja miałem pokazać wam algorytm na zrobienie takiego bota, a zostaje oceniany za "pisanie zmiennych w różnych językach" :D Osobiście pisze wszystkie zmienne po angielsku (z przyzwyczajenia), ale w tym poradniku nie bez powodu nie stosowałem takich nazw. Dla początkujących jest dużo prościej to zrozumieć.

Edytowane przez Dave

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Dave

Pod jakim względem wydajniejsza była by w tym przypadku?

 

Owszem zgodzę się, że możemy te dane pobrać tylko raz na samym początku i działało by to optymalniej niż aktualnie, ale zastanawia mnie czym różni się funkcja getElement od tej co podałem :)

 

Z tego co mi wiadomo to każda funkcja nie zależnie od zastosowania w cale nie zużywa więcej ani mniej zasobów, a obydwa zapisy są prawdę mówiąc identyczne, z jednym wyjątkiem. Funkcja posiada wewnętrzne zmienne (te które są podawane w parametrach) i wywołanie funkcji powoduje iż te parametry są najpierw klonowane do innej komórki pamięci, dzięki czemu wszelkie operacje pod tymi zmiennymi nie wpływają na zmienne po za funkcją.

Edytowane przez Dave

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Matex
Dnia 6/3/2017 o 23:36, Eros_PL napisał:

W programowaniu nazwy zmiennych mają znaczenie ponieważ piszesz Aplikacje OpenCode na dużą skale i ludzie zaglądają do kodu i sprawdzają czy jest czytelny a no raczej zmienne raz w tym języku raz w tym nie są najlepsze. print_r luzik poprostu napisałem zdarza się ponieważ nie raz zostawiam takie rzeczy. A co zapisu 

$this->channelList("-topic -flags -voice -limits -icon -secondsempty")['data']

Się nie zgodzę ponieważ funkcja getElement jest wydajniejsza i ma więcej zastosowań.

To jest opinia nie hejt również się uczę i nie jestem lepszy nie uważam się za developera ale lubię się wypowiadać na takie tematy. Powiedzmy sobie szczerze Polskie kodowanie botów jest tragiczne i Elo.

 

Gdyby znaczenie miało w jaki sposób uzyskamy dane ze zmiennej XD Nie będzie nic wydajniejsze od wbudowanej funkcjonalności w PHP. Możesz sobie zbenchmarkować tą samą tablice przy użyciu podanego sposóbu przez @Dave i przy użyciu funkcji z klasy.

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Dave

A jeśli chodzi o nazwy zmiennych to w jakim języku wolicie abym pisał zmienne?

Dla mnie to naprawdę nie problem pisać takie zmienne  po angielsku, ale zastanawiam się czy będzie to dla was na tyle zrozumiałe np.

free_channel_count czy ile_wolnych_kanalow

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Gość K-Scripts

Widzę, że pisałeś to bardzo szybko, dzięki czemu popełniłeś tutaj masę błędów :)

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Dave

Jak są błędy ort. to przepraszam najmocniej :D

Zamieściłem ten kod, aby inni mogli go rozpracować i ewentualnie dopracować. Sporo można w nim poprawić i ulepszyć, a mi osobiście wystarcza taka wersja jaka jest aktualnie :) Jest ona bardzo mało optymalna na pewno, ale dla mnie osobiście to nie problem. Może macie jakieś propozycję ulepszenia takiego bota to z chęcią posłucham :)

Jak znajdę chwilkę to postaram się zamieścić wersję poprawiona (skróconą i optymalniejszą)

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Gość K-Scripts

Nigdy nie zwracam uwagi na błędy ortograficzne w takich skryptach :)

Wygląda to dość ciekawie, w wolnej chwili sprawdzę :)

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Dave
Spoiler

 

<?php
$config =[
	"min"=>2,
	"max"=>10,
	"channel"=>[
		"unlimited"=>82,
		2=>85,
		3=>86,
		4=>87,
		5=>88
	],
	"ilewolnych"=>2
]; 
foreach($config['channel'] as $channellmax=>$channelid){
	$countchannel = 0;
	$emptychannel = 0;
	$channels = $this->channelList("-topic -flags -voice -limits -icon -secondsempty")['data'];
	$channels=$channels['data'];
	foreach($channels as $channel)
		if($channel['pid']==$channelid){
			if($channel['total_clients']==0){
				$emptychannel++;
				$lastemptychannel = $channel;
			}
			$lastchannel=$channel;
			$countchannel++;
		}
		if (($emptychannel<$config['ilewolnych'])&&($countchannel<$config['max'])) {
			$channel_number=1;
			foreach($channels as $channel) if($channel['pid']==$channelid) $channel_number++;
			if($channel_number<10) $channel_number="0".$channel_number;
			if ($channellmax=='unlimited') {
				$this->channelCreate([
					'channel_name' => " • Kanał Publiczny [ ".$channel_number." ]",
					'channel_flag_maxclients_unlimited' => 1,
					'channel_flag_permanent'=>1,
					'channel_codec_quality'=>10
					]);
			} else {
				$this->channelCreate([
					'channel_name' => " • Kanał Publiczny [ ".$channel_number." ]",
					'channel_flag_maxclients_unlimited' => 0,
					'channel_maxclients' => $channellmax,
					'channel_flag_permanent'=>1,
					'channel_codec_quality'=>10
					]);
			}
			foreach($this->channelList()['data'] as $channel) {
				$lastchannellcreate=$channel['cid'];
				if($channel['pid']==$channelid) $order = $channel['cid'];
			}
			$this->channelMove($lastchannellcreate,$channelid,$order);
		} else if(($emptychannel>)&&($countchannel>$config['min'])) {
			if($lastchannel['total_clients']==0) $this->channelDelete($lastchannel['cid']);
			else {
				foreach($this->clientlist("-topic -flags -voice -limits -icon -secondsempty")['data'] as $client) {
					if ($client['cid']==$lastchannel['cid']) {
						$this->clientMove($client['clid'],$lastemptychannel['cid']);
					}
				}
			}
		}
	}
}

 

 

A oto taka bardziej ogarnięta wersja, tylko nie sprawdzałem czy działa :D Można by jeszcze ogarnąć między innymi fakt iż nie powinniśmy robić channelMove, a taka własność powinna się zawierać już w channelCreate

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Venden!

Fajny skrypt! Widziałem go w już w kilku botach ale osobom które ich nie mają napewno się przyda.

Leci + za włożona pracę

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
orkin

Ale formatowanie kodu to takie średnie. Chcesz żeby kod był jak najbardziej zrozumiały, a nie potrafisz się trzymać standardów PSR.

Plus niepotrzebnie podajesz tyle flag przy channelList, a ilość pętli i ifów prawdopodobnie dałoby radę jeszcze zredukować.

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
dafqq

Przyda się ?

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi

Dołącz do dyskusji

Możesz dodać zawartość już teraz a zarejestrować się później. Jeśli posiadasz już konto, zaloguj się aby dodać zawartość za jego pomocą.

Gość
Dodaj odpowiedź do tematu...

×   Wklejono zawartość z formatowaniem.   Usuń formatowanie

  Dozwolonych jest tylko 75 emoji.

×   Odnośnik został automatycznie osadzony.   Przywróć wyświetlanie jako odnośnik

×   Przywrócono poprzednią zawartość.   Wyczyść edytor

×   Nie możesz bezpośrednio wkleić grafiki. Dodaj lub załącz grafiki z adresu URL.


  • Ostatnio przeglądający   0 użytkowników

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


×

Powiadomienie o plikach cookie