как понять static decl Handle..

NagarD

Участник
Сообщения
411
Реакции
184
Объясните пожалуйста.
1. Первое что меня интересует - как мне понимать Handle и decl.

PHP:
new Handle:EnabledMode = INVALID_HANDLE;
decl String:userid[15];

2. Что за модификаторы (может и не модификаторы) static и stock
О статик понял что это типа протект переменная её не будет видно вне функции и она инициализируеться только один раз.

PHP:
static iPrevButtons[MAXPLAYERS+1];

stock Function()
{
     //
}

3. Волшебные константы MAXPLAYERS и MaxClients

PHP:
for (new i = 1; i <= MaxClients; i++)
{
    if (IsPlayerAlive(i)){
        //
    }
}
new iPrevButtons[MAXPLAYERS+1];

Интересно как MaxClients делает i индексом игрока?

4. Что такое &?

PHP:
public Action:OnPlayerRunCmd(client, &buttons, &impulse, Float:vel[3], Float:angles[3], &weapon) 
{
    if (buttons & IN_USE)
    {
        //
    }
}

Наверное все знают пример с коробкой и дыркой в ней. Коробка - область в памяти, дырка - ссылка на эту область. Хотелось бы увидеть что-то подобное
 

R1KO

fuck society
Сообщения
9,457
Реакции
7,786
  • Команда форума
  • #2
NagarD, 3. Индекс игрока может быть от 1 до 64 (вроде бы), а MaxClients это по сути и есть число 64, и ты цикло перебираешь все числа от 1 до 64 с условием IsClientInGame, и если число проходит эту проверку то оно есть индексом игрока.
if (IsPlayerAlive(i)) - так нельзя делать. Не известно в игре ли игрок. Будет куча ошибок в логе. Сначала надо IsClientInGame.
MAXPLAYERS - Это тоже вроде число 64 но к нему прибавляем 1 т.к. первый индекс массива будет 0.

decl - создаешь переменную не присваивая ей значения или что-то в этом роде
 

NagarD

Участник
Сообщения
411
Реакции
184
R1KO, выходит на сервере может быть максимум 64 игрока? Оффтоп
 

R1KO

fuck society
Сообщения
9,457
Реакции
7,786
  • Команда форума
  • #4
NagarD, да
Decl on Local Arrays

Here is another example, using OnGameFrame:
public OnGameFrame()
{
new String:buffer[4096];
}
When you declare an array with new, Pawn initializes each slot to 0. Let's say writing to an array slot costs 1 unit of time. Declaring this array therefore costs a fixed 4096 units of time. Is that a problem? Well, the game server ticks at 33 times per second. Therefore this costs about 150,000 units of time per second. If a "unit of time" is a nanosecond, we could estimate this costing around 0.1 milliseconds. That could be a lot depending on what your plugin does. You get about 15ms per frame, of which about half is used by the server. If you use more than this time, you could start delaying frames.
Let's say that you have declared this big array inside a loop, inside OnGameFrame, and you are worried about the cost. The preferred way of solving this is to use decl instead of new, which does not perform any initialization:
public OnGameFrame()
{
decl String:buffer[4096];
}
NOTE: You must be very careful not to read from uninitialized variables. They will contain garbage, and you could crash the server by attempting to print or operate on garbage string
You should only use decl on performance-critical arrays. It is never needed anywhere else.
Насколько я понял он работает быстрее new и создает переменную с хламом внутри
 
Последнее редактирование:

KorDen

Atra esterní ono thelduin!
Сообщения
2,142
Реакции
1,424
1. Handle - типизатор переменной (фактически как и String) - указывает что в переменной хранится ссылка наданныеь (на переменную, на таймер, на данные Trie/Array/KeyValues)
Decl - начну с new. new при объявлении переменной гарантированно выставляет ей значение 0. Однако если брать тот же массив или строку, то нет смысла их полностью инициализировать, если в них сразу будут записываться данные. decl объявляет переменную, но изначально в ней будет мусор. Однако быстрее.
decl не работает для глобальных переменных.
Для строк (String) можно адже делать самодельную инициализацию нулем гораздо быстрее (если вдруг может случиться что значение не будет прописано)
decl String:test[255];
test[0]=0;
Это быстрее, и для строк аналогично new String:test[255]; по результату. Фактически да, дальше будет мусор, но строки обрабатываются до ноль-символа, и поэтому это аналогично.

2. stock - часто используется в библиотеках типа morecolors или SMLib. Если stock-функция не вызывается нигде, то при компиляции она не будет вкомпилена в плагин.
static - оптимизация. Например в функции OnPlayerRunCmd постоянно создается локальная переменная - это лишние затраты. А так фактически получится как глобальная переменная, т.е. она создастся один раз. Но при этом глобально к ней обратиться нельзя.

3. индекс игрока, (а так же индекс энтити тела живого игрока, который равен индексу игрока) - как уже сказал рико - от 1 до 64. 0 - консоль, больше 64 уже идут индексы энтитей мира (те же бочки и любые другие объекты т.д.) Фактически да, в Source максимум 64 игрока (исключение - Garry's Mod (128), но под него нет SM), иногда 65 когда STV.
MAXPLAYERS - константа, вшивается при компиляции (64)
MaxClients - это не константа, это серверная глобальная переменная (не переменная всмысле sv_ и т.д., а именно внутренняя в SM), равна количеству слотов на сервере. Т.е. если сервер запущен на 32 человека, то цикл будет пробегать от 1 до 32, а не до 64.

4. & - передача по адресу (по сути аналогична Си, но не нужно явно разадресовывать такие переменные).
Т.е. если обычно ты передаешь в функцию копию переменной, и изменения идут только локально, то здесь ты передаешь оригинальную переменную, и если ее изменять, то будет изменяться оригинал Пример:
PHP:
func1()
{
	new a=5;
	PrintToServer("%d\n",a); // 5
	func2(a);
	PrintToServer("%d",a); //10
}
func2(&num)
{
	num=num+5; // или можно num=10; и т.д.
}
 

NagarD

Участник
Сообщения
411
Реакции
184
C decl думаю абсолютно разобрался. По сути decl просто размечает память, но не форматирует её, а new форматирует.
stock выходить в плагинах вообще не нужно, только во всяких расширениях.
Если правильно знаю, то MAXPLAYERS не глобальная константа, а дефайн глобальный, так выходит?
MaxClients - ну это просто. Могу добавить, что она еще динамическая.
Немного понял о передачи по ссылке.
А вот Handle вообще в голову не влазит.
 

FrozDark

Участник
Сообщения
1,769
Реакции
2,050
проще говоря, Handle указатель на ячейку с памятью, например, переменных

Оффтоп - Handle содержит переменную, которая выделяется через С++. Просто SourcePawn не может управлять памятью напрямую и содержит только статическое.
 

NagarD

Участник
Сообщения
411
Реакции
184
FrozDark, хорошо, а зачем Handle нужен? Если объявить Handle не приравняв к INVALID_HANDLE, что будет? Оффтоп
 

Reiko1231

AlexTheRegent
Сообщения
508
Реакции
1,335
В четвертом неправильно ответили, для твоего вопроса это не передача по адресу, а побитовое И.
Здесь в переменной buttons находятся все нажатые клавиши (их значения, если быть точнее. ибо можно забиндить "использовать" на Z, и тогда IN_USE будет означать, что нажата Z, а не E), и через & проверяется, содержится ли там IN_USE флаг. Вообщем википедия, статья про битовые операции, а то я чувствую, что объяснил не очень.
 

R1KO

fuck society
Сообщения
9,457
Реакции
7,786
  • Команда форума
  • #10
FrozDark, хорошо, а зачем Handle нужен? Если объявить Handle не приравняв к INVALID_HANDLE, что будет? Оффтоп

Ничего не будет.
Так же как и
PHP:
new i;
При создании присвоит i значение 0
Точно так же и
PHP:
new Handle:hCvar;
При создании присвоит hCvar значение INVALID_HANDLE
 

KorDen

Atra esterní ono thelduin!
Сообщения
2,142
Реакции
1,424
C decl думаю абсолютно разобрался. По сути decl просто размечает память, но не форматирует её, а new форматирует.
Да
stock выходить в плагинах вообще не нужно, только во всяких расширениях.
Не в расширениях, а в подключаемых библиотеках (файлах .inc)
Если правильно знаю, то MAXPLAYERS не глобальная константа, а дефайн глобальный, так выходит?
Тут ты немного смешал в кучу. Поясню. Есть фраза "Пианино делает музыку". Тогда твоя фраза была бы "MAXPLAYERS выходит не музыка, а пианино глобальное?" - #define - это объявление константы. и MAXPLAYERS это константа, но да, фактически она объявляется #define в одном из стандартных включаемых файлов.
Точно так же ты же не называешь переменную "Это нью" (от объявления new)
MaxClients - ну это просто. Могу добавить, что она еще динамическая.
Она устанавливается при запуске сервера и фактически равна значению +maxplayers в строке запуска (либо прибавляется один если STV включен)
Немного понял о передачи по ссылке.
Да, тут Reiko правильно объяснил, я не о том & говорил, я о тех, которые в заголовке функции.
А вот Handle вообще в голову не влазит.
Ну ты же сам объяснил точь-в-точь :)
Коробка - область в памяти, дырка - ссылка на эту область.
 

KorDen

Atra esterní ono thelduin!
Сообщения
2,142
Реакции
1,424
Про побитовые операции (buttons & IN_USE), попробую объяснить попроще и нагляднее.
Мне кажется лучше привести примером админские флаги, проще будет понять.
Смотри, предположим у админа флаги "abce"
В двоичном представлении, которое вернет GetUserFlagBits(client), это выглядит как 10111.
C-подобный:
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 1 1 - битовое представление
t s r q p o z n m l k j i h g f e d c b a - флаги
Далее мы применяем маскирование.
Маска - это собственно то что идет после &. если в маске 0, то в результате будет всегда 0, если в маске 1 - то будет то что в переменной (т.е. если был 0 - останется 0, если была 1 - останется 1)
Например мы берем GetUserFlagBits(client) & ADMFLAG_ROOT
C-подобный:
t s r q p o z n m l k j i h g f e d c b a
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 1 1 - флаги админа
0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 - маска, проще говоря двоичное представление константы ADMFLAG_ROOT
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 = 0 = false - результат
А если берем GetUserFlagBits(client) & ADMFLAG_GENERIC
C-подобный:
t s r q p o z n m l k j i h g f e d c b a
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 1 1 - флаги админа
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 - маска, проще говоря двоичное представление константы ADMFLAG_GENERIC
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 = 10 = true - результат
Помни, что false = 0, а все остальное - true. Т.е. в данном случае где будет GENERIC вернется true, т.к. у админа есть этот флаг и он выделяется по маске
 

R1KO

fuck society
Сообщения
9,457
Реакции
7,786
  • Команда форума
  • #13
Не буду создавать новую тему.
Тоже кое что спрошу. Код из Weapon Restrict:
PHP:
if(!g_bSpamProtectPrint[client])
	{
		if(Restrict_IsSpecialRound() && !Restrict_AllowedForSpecialRound(id))
		{
			PrintToChat(client, "\x01\x0B\x04[SM] %T %T", weaponNames[_:id], client, "SpecialNotAllowed", client);
		}
		else if(team == CS_TEAM_CT)
		{
			PrintToChat(client, "\x01\x0B\x04[SM] %T %T", weaponNames[_:id], client, "IsRestrictedPickupCT", client, Restrict_GetRestrictValue(team, id));
		}
		else
		{
			PrintToChat(client, "\x01\x0B\x04[SM] %T %T", weaponNames[_:id], client, "IsRestrictedPickupT", client, Restrict_GetRestrictValue(team, id));
		}
		g_bSpamProtectPrint[client] = true;
		CreateTimer(PRINTDELAY, ResetPrintDelay, client);
	}
Мне не понятна роль _:id
 

KorDen

Atra esterní ono thelduin!
Сообщения
2,142
Реакции
1,424
R1KO, хе, странно, обычно это не нужно.. Хотя.. скинь строчку объявление этого самого id...
 

R1KO

fuck society
Сообщения
9,457
Реакции
7,786
  • Команда форума
  • #15
KorDen, вот еще
PHP:
new defaultValuesCT[_:WeaponID];
new defaultValuesT[_:WeaponID];
new perPlayer[_:WeaponID][MAXPLAYERS+1];
new bool:g_bOverideT[_:WeaponID];
new bool:g_bOverideCT[_:WeaponID];
//Convar Handles
new Handle:hRestrictCVarsT[_:WeaponID-4];//No shield, No None, No Defuser, No SCAR17
new Handle:hRestrictCVarsCT[_:WeaponID-4];//No shield, No None, No C4, No SCAR17
new Handle:g_version = INVALID_HANDLE;
new CvarArrayHandleValCT[_:WeaponID];
new CvarArrayHandleValT[_:WeaponID];


//
for(new i = 0; i < _:WeaponID; i++)
	{
		if(WeaponID:i == WEAPON_NONE || WeaponID:i == WEAPON_SHIELD || WeaponID:i == WEAPON_SCAR17 || AllowedGame[WeaponID:i] == -1 || (g_iGame == GAME_CSS && (AllowedGame[WeaponID:i] != 1 && AllowedGame[WeaponID:i] != 2)) || (g_iGame == GAME_CSGO && (AllowedGame[WeaponID:i] != 1 && AllowedGame[WeaponID:i] != 3)))
		{
			CvarArrayHandleValCT[WeaponID:i] = -1;
			CvarArrayHandleValT[WeaponID:i] = -1;
			continue;
		}
		if(WeaponID:i != WEAPON_DEFUSER)
		{
			if(WeaponID:i != WEAPON_C4)
			{
				Format(cvar, sizeof(cvar), "sm_restrict_%s_t", weaponNames[WeaponID:i]);
			}
			else
			{
				Format(cvar, sizeof(cvar), "sm_restrict_%s", weaponNames[WeaponID:i]);
			}
			Format(desc, sizeof(desc), "-1 = unrestricted, 0 = restricted, positive numbers = number allowed for Terrorists . Weapon:%s", weaponNames[WeaponID:i]);
			hRestrictCVarsT[x] = CreateConVar(cvar, "-1", desc);
			CvarArrayHandleValT[WeaponID:i] = x;
			x++;
		}
		else
		{
			CvarArrayHandleValT[WeaponID:i] = -1;
		}
		if(WeaponID:i != WEAPON_C4)
		{
			if(WeaponID:i != WEAPON_DEFUSER)
			{
				Format(cvar, sizeof(cvar), "sm_restrict_%s_ct", weaponNames[WeaponID:i]);
			}
			else
			{
				Format(cvar, sizeof(cvar), "sm_restrict_%s", weaponNames[WeaponID:i]);
			}
			Format(desc, sizeof(desc), "-1 = unrestricted, 0 = restricted, positive numbers = number allowed for Counter-Terrorists. Weapon:%s", weaponNames[WeaponID:i]);
			hRestrictCVarsCT[y] = CreateConVar(cvar, "-1", desc);
			CvarArrayHandleValCT[WeaponID:i] = y;
			y++;
		}
		else
		{
			CvarArrayHandleValCT[WeaponID:i] = -1;
		}
	}

//
 

KorDen

Atra esterní ono thelduin!
Сообщения
2,142
Реакции
1,424
R1KO, а, WeaponID это по идее enum... но тогда не понятно зачем делать _: если i и так обычная переменная... Короче надо смотреть все в комплексе. Но в общем - это разные типы, _ обозначает отсутствие специального типа
 

NagarD

Участник
Сообщения
411
Реакции
184
R1KO, Тоже самое, что и String:var
_ обозначает отсутствие специального типа

Добавлено через 43 минуты
И так, продолжим. Есть модификаторы переменных srting, handle, decl, float, даже enum, как сказано выше, и другие - области в памяти. Ключевым srting словом мы задаем тип переменной (а кому задаем?). Если тип строка, то это говорит (а кому не знаем), что те биты в памяти формируют символы, буквы, числа. Если Handle, то, не знаем кто, знает, что в той области памяти находится адрес какой-то сущности, а не число, или строка, так?. Вопрос, а для чего это нужно?
 
Последнее редактирование:

KorDen

Atra esterní ono thelduin!
Сообщения
2,142
Реакции
1,424
И так, продолжим. Есть модификаторы переменных srting, handle, decl, float, даже enum, как сказано выше, и другие - области в памяти. Ключевым srting словом мы задаем тип переменной (а кому задаем?). Если тип строка, то это говорит (а кому не знаем), что те биты в памяти формируют символы, буквы, числа. Если Handle, то, не знаем кто, знает, что в той области памяти находится адрес какой-то сущности, а не число, или строка, так?. Вопрос, а для чего это нужно?

Ну прям "Тот-Кого-Нельзя-Называть" :-D
Вообще это указатели на предназначение переменной. Указываем мы это компилятору. Однако String это все же больше тип.
Поясню - стандартно при объявлении через new выделяется 4 байта (int). А при указании String на каждую ячейку выделяется 1 байт.
Точно так же ты можешь в качестве строки использовать new a[4096] вместо new String:a[4096], однако тогда будет выделено 4*4096=16 килобайт, вместо 4х, и получается что 12 килобайт будут попусту висеть.

float задает метод хранения данных - тут стоит почитать про методы сохранения целых чисел и чисел с плавающей точкой в памяти компьютера. Тут компилятор будет ругаться что tag Mismatch для удобства программиста, потому что иначе в переменных будет каша, если присваивать int=float и наоборот.

handle указывает что это адрес в памяти, а не число. Никаких специфичных изменений в принципе сохранения нет относительно стандартного, однако помогает не путаться.
 

Jak ozdoba na torcie

Как украшение на торт
Сообщения
25
Реакции
11
Ну прям "Тот-Кого-Нельзя-Называть" :-D
Вообще это указатели на предназначение переменной. Указываем мы это компилятору. Однако String это все же больше тип.
Поясню - стандартно при объявлении через new выделяется 4 байта (int). А при указании String на каждую ячейку выделяется 1 байт.
Точно так же ты можешь в качестве строки использовать new a[4096] вместо new String:a[4096], однако тогда будет выделено 4*4096=16 килобайт, вместо 4х, и получается что 12 килобайт будут попусту висеть.

float задает метод хранения данных - тут стоит почитать про методы сохранения целых чисел и чисел с плавающей точкой в памяти компьютера. Тут компилятор будет ругаться что tag Mismatch для удобства программиста, потому что иначе в переменных будет каша, если присваивать int=float и наоборот.

handle указывает что это адрес в памяти, а не число. Никаких специфичных изменений в принципе сохранения нет относительно стандартного, однако помогает не путаться.

Дополнение: Handle это 4bitжое число и другой плагин не может использовать его (Если его не клонировать).
 

FrozDark

Участник
Сообщения
1,769
Реакции
2,050
каждому из String, Handle, bool можно перевести в простой integer

Т.е. если я сделаю new Handle:hCvar = Handle:11354;
можно вывести Handle как integer.
В итоге PrintToChatAll("%d", _:hCvar) выведет в чат 11354 и не будет никаких ошибок при компиляции

Я называю это _: опускание префикса

Так же можно из bool сделать Handle или String просто выставив нужный префикс
 
Сверху Снизу