Jump to content

návod Scydovy YSI návody | #7 | y_utils, y_va, y_iterate, y_inline [**]


Scydo

Recommended Posts

YSI_Core\y_utils
YSI_Coding\y_va + YSI_Coding\y_inline
YSI_Data\y_iterate / YSI_Data\y_foreach
**
***

Tak jo. Tyto 4 includy (plus jeden co je jen alternativa), sice obsahují mnoho dalších zajímavých vymožeností, nicméně, chci tu pouze ukázat to nejzajímavější a to, co s velkou pravděpodobností někdo použije při tvorbě FS/GM.

YSI_Core\y_utils

A začneme s y_utils. Jak už ang. slovo "utils" naznačuje, jde o nástroje, přesněji o hromadu užitečných funkcí. Většinou takové funkce jste mohli vidět na SA-MP fóře ve topicu "Useful functions":
 

Spoiler

StrToLower();
StrToUpper();
Random();
RandomFloat();
StripNL();
StripL();
Strip();
endofline();
chrfind();
chrfindp();
bernstein();
ishex();
returnstringarg();
va_return();
isnumeric();
hexstr();
boolstr();
binstr();
ReturnPlayerName();
ftouch();
InterpolateColour();
SkipWhitespace();
IS_IN_RANGE();
NOT_IN_RANGE();
ceildiv();
floordiv();
isnull();
isodd();
iseven();
strcpy();
GetIP();

 

A to je jen ten seznam funkcí, co jsem našel :d. Kdoví, které tam ještě jsou. Tak zkusíme ty nejzajímavější/nejužitečnější:
1. isnull() pro parametry do příkazů:

if (isnull(params)) return ...;

2. StrToUpper() pro změnu všech znaků písmen na velká a StrToLower() pro změnu všech znaků písmen na malá:

format(str, sizeof str, "Máš zapnuté/vypnuté načítání? %s", 
	Bit_Get(IsOnLoad, playerid) == true ? StrToUpper("true") : StrToUpper("false"));

// Anti CapsLock
va_SendClientMessageToAll(-1, "%s %s", ReturnPlayerName(playerid), StrToLower(text));

3. Random() pro náhodné číslo a RandomFloat() pro náhodné desetinné číslo:

Random(min, max);
RandomFloat(Float:min, Float:max, dp = 2);

Argument dp je ohledně zaokrouhlení výsledné hodnoty. Pro lepší představu kód:

printf("%.3f %.3f %.3f %.3f", RandomFloat(1.0, 10.0, 0), RandomFloat(1.0, 10.0, 1), RandomFloat(1.0, 10.0, 2), RandomFloat(1.0, 10.0, 3));
printf("%.3f %.3f %.3f %.3f", RandomFloat(1.0, 10.0, 0), RandomFloat(1.0, 10.0, 1), RandomFloat(1.0, 10.0, 2), RandomFloat(1.0, 10.0, 3));
printf("%.3f %.3f %.3f %.3f", RandomFloat(1.0, 10.0, 0), RandomFloat(1.0, 10.0, 1), RandomFloat(1.0, 10.0, 2), RandomFloat(1.0, 10.0, 3));
printf("%.3f %.3f %.3f %.3f", RandomFloat(1.0, 10.0, 0), RandomFloat(1.0, 10.0, 1), RandomFloat(1.0, 10.0, 2), RandomFloat(1.0, 10.0, 3));
printf("%.3f %.3f %.3f %.3f", RandomFloat(1.0, 10.0, 0), RandomFloat(1.0, 10.0, 1), RandomFloat(1.0, 10.0, 2), RandomFloat(1.0, 10.0, 3));
printf("%.3f %.3f %.3f %.3f", RandomFloat(1.0, 10.0, 0), RandomFloat(1.0, 10.0, 1), RandomFloat(1.0, 10.0, 2), RandomFloat(1.0, 10.0, 3));
printf("%.3f %.3f %.3f %.3f", RandomFloat(1.0, 10.0, 0), RandomFloat(1.0, 10.0, 1), RandomFloat(1.0, 10.0, 2), RandomFloat(1.0, 10.0, 3));

A výsledek:

7.000 4.400 8.460 1.365
1.000 9.300 8.399 8.619
7.000 4.900 3.529 4.157
2.000 7.400 4.309 4.928
1.000 7.000 4.699 3.971
6.000 1.700 8.949 2.434
5.000 2.200 9.359 5.991

4. isnumeric() jestliže je řetězec znaků číslo:

if (!isnumeric(inputtext)) return ...;

5. GetIP() vrátí IP hráče(ne pouze v číslech!):

va_SendClientMessage(..., "%s", GetIP(playerid));

6. IS_IN_RANGE jestliže hodnota je v rozmezí a NOT_IN_RAGE jestliže není:

if (IS_IN_RANGE(10, 1, 100) == true) return print("Cislo 10 je v rozmezí!");
if (NOT_IN_RANGE(10, 1, 9) == true) return print("Cislo 10 není v rozmezí!");

7. A nebo několik return ze řetězce hodnot do určitého datového typu:

hexstr(string[]);
boolstr(string[]);
binstr(string[]);

A mnohem více...

YSI_Coding\y_va

Include y_va pro změnu obsahuje možnost si udělat vlastní formátované zprávy, funkce apod. Příklad, běžného formátování zpráv:

new string[144 + 1];
format (string, sizeof (string), "Bla bla bla %s %i %d", ReturnPlayerName(playerid), Random(10), Random(100));
SendClientMessage(playerid, -1, string);

Další možnosti byly pomocí maker, nebo vzít proměnnou string jako globální proměnnou, nebo pomocí #emit. Nicméně pro obyčejné uživatelé to je velmi složitě.
Include y_va nabízí jednodušší způsob, jak si takové funkce udělat. Ukázka použití funkce zpráv ze y_va:

va_SendClientMessage(playerid, -1, "Bla bla bla %s %i %d", ReturnPlayerName(playerid), Random(10), Random(100));

A to není všechno. Nejen, že je to jednodušší, ale také rychlejší něž obyčejně či přes marka.
Uživatel si může udělat vlastní pomocí va_format a va_start. Ukázka, jak je udělané va_SendClientMessage():

va_SendClientMessage(playerid, colour, const fmat[], {Float, _}:...) {
	new
		str[145];
	va_format(str, sizeof (str), fmat, va_start<3>);
	return SendClientMessage(playerid, colour, str);
}

S tím, že formátování samotné fce je ve va_format a argument va_start<3> zastává pořadí, kdy se začnou přidávat hodnoty za specifikátory.
Samozřejmě, nemusíte si takové funkce tvořit. Většina už je předdefinovaná. Seznam:

va_print(const fmat[], va_args<>);
va_SendPlayerMessageToPlayer(playerid, senderid, const fmat[], va_args<>);
va_SendPlayerMessageToAll(senderid, const fmat[], va_args<>);
va_SendClientMessage(playerid, colour, const fmat[], va_args<>);
va_SendClientMessageToAll(colour, const fmat[], va_args<>);
va_GameTextForPlayer(playerid, const fmat[], time, style, va_args<>);
va_GameTextForAll(const fmat[], time, style, va_args<>);
va_SetTimerEx(const function[], interval, bool:repeating, const fmat[], va_:STATIC_ARGS);
va_CreatePlayerTextDraw(playerid, Float:x, Float:y, fmat[], va_args<>);
va_TextDrawCreate(Float:x, Float:y, fmat[], va_args<>);
va_CallLocalFunction(const function[], const fmat[], va_:STATIC_ARGS);
va_CallRemoteFunction(const function[], const fmat[], va_:STATIC_ARGS);

YSI_Data\y_foreach / YSI_Data\y_iterate
Pokud jde rozdíl mezi foreach a iterate, tak žádný není. Jen foreach je více známé, protože je starší.

y_iterare se dělí na dvě možnost použití.
A. Lepší práce s cykly včetně s již předdefinovanýma podmínkama (například u cyklu pro hráče se cyklí pouze hráči).
B. Udělat si vlastní hodnotu, co se bude cyklit.

A. Nejdříve práce s cykly. Normální cyklus všichni asi známe, příklad:

for(new i; i<MAX_PLAYERS; i++) {
	if(IsPlayerConnected(i)) {

Pak je tu možnost s novou funkcí, která vrátí nejvyšší id hráče na serveru:

for(new i = 0, j = GetPlayerPoolSize(); i <= j; i++) {
	if(IsPlayerConnected(i)) {

A teď ukázka přes foreach:

foreach (new i: Player) {

Jednoduché že? A obsahuje to i samozřejmě podmínku zda je to hráče a jestliže je online. Jinak používání je úplně stejné jako u obyčejného cyklu:

foreach (new i: Player) {
	if (AdminLevel[i] > 10) {
		// Sample code
	}
}

Slovo "Player" je takzvané iter tag aka typ. Zde ještě je seznam dalších iter tagů, které obsahuje:

foreach (new v: Vehicle)

foreach (new b: Bot)

foreach (new a: Actor)

foreach (new c: Character)

// Další části knihovny:
  
foreach (new p: Bit(bit_jméno))
  
foreach (new g: Group(gAdmins))

foreach (new i: Range(10,100))
  
// Potom několik speciálních například:

// Cyklus vrátí každého index v poli které obsahuje 0.
foreach (new i : Null(pole))

// Cyklus vrátí každého index v poli které NEobsahuje 0.
foreach (new i : NonNull(pole))

// Cyklus půjde pozpátku
foreach (new i : Reverse(10))

// Mocniny. 1, 2, 4, 8, 16...
foreach (new i: Powers(2))

// 5x náhodná čísla
foreach (new i: Random(5))

// Fibonacciho posloupnost 
foreach (new i: Fib())

// Cyklus skončí jakmile narazí index rovnají se číslu, takže 5
new pole[] = { 1, 2, 3, 4, 5, 6, 7}
foreach (new i: Until(6, pole))

// Cyklus vypíše všechny indexy na kterých se nachází číslo 6
new pole[] = { 6, 1, 9, 3, 4, 6, 6}
foreach (new i: Filter(6, pole))

B. Teď je další možnost, kdy si lze přidat vlastní iter tag. Zkusíme si například udělat příkaz /admins. Začneme deklarací našeho iteru:

// Maximální počet hodnot v iteratoru:
#define MAX_ADMINS (10)

// Proměnná s tagem Iterator: a maximální počet hodnot v ostrých závorkách:
new 
	Iterator:Admins<MAX_ADMINS>

Než ale budeme pokračovat, vysvětlení pár funkcí, které y_iterate obsahuje:

// Zjistí volnou hodnotu v iteratoru:
Iter_Free(Iterator:Name<>);

// Jestliže iterator tuhle hodnotu už obsahuje:
Iter_Contains(Iterator:Name<>, value);

// Přidá do iteratoru danou hodnotu:
Iter_Add(Iterator:Name<>, value);

// Odebere z iteratoru danou hodnotu:
Iter_Remove(Iterator:Name<>, value);

// Zjistí počet vložených iteratoru:
Iter_Count(Iterator:Name<>);

// Pročistí celý iterator od všech hodnot:
Iter_Clear(IteratorArray:Name[]<>);

// Zjistí velikost iteratoru,
// (Jestliže na všechno používáte MAX_něco makro tak není co řešit):
Iter_Size(Iterator:Name<>);

Teď, jestliže je hráč teda náš admin, musíme ho do našeho iteratoru přidat. Můžeme například poté, co se připojí na server:

public OnPlayerConnect(playerid) {
	LoadPlayerData(playerid); // <-- Udělaná nějaká naše funkce na načítaní údajů hráče
	if (AdminLevel[playerid] > 0) {
		if (Iter_Count(Admins) < MAX_ADMINS) Iter_Add(Admins, playerid);
		else return printf("Něco je špatně. Asi máš moc Adminů v Admintýmu! %i", Iter_Count(Admins));
	}
	return 1;
}

Samozřejmě, po odpojení ho musíme odebrat, jinak se nám budou stále přidávat další:

public OnPlayerDisconnect(playerid, reason) {
	if (Iter_Contains(Admins, playerid)) Iter_Remove(Admins, playerid);
	return 1;
}

A nakonec, jestliže je se vypne FS či server, tak pro jistotu tenhle iterator pročistit. Lze to i po spuštění:

public OnFilterScriptExit() {
	Iter_Clear(Admins);

A teď, když náš iterator obsahuje POUZE hráče, co mají adminlevel, můžeme s ním snadno pracovat:

YCMD:admins(playerid, o[], help) {
	if (Iter_Count(Admins) == 0) return SendClientMessage(playerid, X11_RED, "Momentálně není online žádný Admin!");
	foreach (new i: Admins) {
		if (IsPlayerAdmin(i)) va_SendClientMessage(playerid, X11_YELLOW1, "%s [LEVEL %i + RCON]", ReturnPlayerName(i), AdminLevel[i]);
		else va_SendClientMessage(playerid, X11_YELLOW1, "%s [LEVEL %i]", ReturnPlayerName(i), AdminLevel[i]);
	}
	return 1;
}

YSI_Coding\y_inline

Jednouše řečeno, jde o include, kde lze používat vnořené fce, aka funkce ve funkci a velmi často se přitom používá naše kouzelné slovíčko using, a buď inline pro uvnitř a nebo public pro mimo. Takto se VÝBORNĚ hodí na práci s dialogy, protože nikdo nechce ten mega obrovský OnDialogResponse kód.
Je opět několik možností, jak tento inlcude používat. Jde i při tom tvořit vlastní funkce, které se budou volat, nicméně, to už spadá do obtížnosti ****, takže to vynechám. Ale kdo by se o to zajímal, tak více informací zde - odkaz

My se zaměříme, jak to efektivně využít do našeho GM. Jak jsem již psal, výborně se hodí s y_dialogs, protože můžeme volat otevřený dialog a nemusíme ho cpát do fce OnDialogResponse().
Jednu variantu ukázky jsem tu již převedl a to voláním dialogu mimo fce a to ve Přechod z dini/dcmd/jiné na YSI4  (v části o dialogu) a nebo uvnitř fce a to ve Masivní použití knihovny.

Hlavní topic (kdyžtak upraveny na 2020) - odkaz
 

Edited by Scydo
  • Paráda! (+1) 1
  • Děkuji (+1) 1
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...