PDA

Просмотр полной версии : [Урок] Подсчёт размера форматируемой строки



Daniel_Cortez
07.02.2016, 17:46
Меня не раз спрашивали, каким образом я рассчитываю размер строк в своих работах (многие из вас могли видеть всякие на первый взгляд сложные формулы типа "sizeof(fmt_str)-2+11-2+MAX_PLAYER_NAME-2+etc."). Поэтому вместо того, чтобы расписывать это всё для каждого отдельно, будет намного лучше составить для всех один урок.



Ниже приведены преимущества и недостатки описываемого в данном уроке метода подсчёта в сравнении с ручным подсчётом (измеритель длины строки + калькулятор), а также особенности, которые нельзя отнести ни к преимуществам, ни к недостаткам данного метода.

Преимущества:
Прозрачность.
Исключаются ситуации, в которых непонятно, каким образом рассчитывается размер форматного массива. Формула подсчёта всегда находится прямо в коде, и никуда не исчезает, в отличие от результатов, выдаваемых калькулятором.
Поняв принципы, по которым составляется формула, можно легко прочесть саму формулу и убедиться в её корректности.
В принципе это преимущество можно отнести и к ручному подсчёту, но только если тоже записывать размер в виде формулы, а не одним числом (например "31 + (-2 + 4) + (-2 + 11)" или "27 + 4 + 11" вместо "42").

Устойчивость к ошибкам при расчётах.
При измерении длины строки вручную и использовании калькулятора легко допустить ошибку в расчётах. В данном методе такие ошибки исключены, т.к. вместо ручных подсчётов требуется лишь составить формулу - вся "грязная работа" с расчётами перекладывается на компилятор.
Также при ручном подсчёте даже с использованием формулы можно изменить форматную строку, но забыть пересчитать её длину - такой тип ошибок исключается только при объявлении форматной строки в отдельном массиве и использовании оператора sizeof.
С другой стороны, в описываемом в данном уроке методе появляется вероятность ошибки при составлении самой формулы, но такие ошибки отследить и предотвратить куда проще: нужно лишь проверить формулу на соответствие форматной строке - благо, и то, и другое всегда "под рукой", прямо в коде (см. выше).

Готовность к модификации.
При изменении форматного текста вносить изменения в формулу нужно только при добавлении новых спецификаторов или изменении уже имеющихся.
Для сравнения, при ручном подсчёте размер массива придётся пересчитывать при любом редактировании форматной строки.


Недостатки:
Обязательно наличие прямых рук, растущих из нужного места.

Требуется объявлять форматную строку в виде отдельного массива.
На производительность или расход памяти это не влияет, но может плохо сказаться на читаемости кода.


Особенности:
Грамотное использование стека.
Этот фактор нельзя отнести к преимуществам только данного метода, поскольку при ручном подсчёте также можно сократить использование стекового пространства вплоть до необходимого минимума.


Плохая читаемость кода.
Например, такой код:


new string[8 + 4];
format(string, sizeof(string), "Ваш ID: %d", playerid);

... занимает меньше места и может быть проще для восприятия, чем


static const fmt_str[] = "Ваш ID: %d";
new string[sizeof(fmt_str) + (-2 + 4)];
format(string, sizeof(string), fmt_str, playerid);

На самом деле "читаемость" кода - вещь субъективная. При достаточном опыте использования описываемого в данном уроке метода код из второго примера может перестать казаться сложным.

Трудоёмкость.
И ежу понятно, что бездумно написать "new string[145];" куда проще, чем составлять формулы.
В принципе то же самое относится и к ручному подсчёту с помощью калькулятора, да и к любому другому методу подсчёта вообще. Зачем что-то рассчитывать, если можно обойтись максимальной длиной строки ("145" или "MAX_CHATBUBBLE_LENGTH + 1" для SendClientMessage) или ещё чем-то подобным?


Из всего вышеописанного можно сделать (довольно очевидный) вывод: не стоит оптимизировать всё подряд.

Для личных работ я рекомендую использовать подсчёт размера форматного массива только в критических случаях - например, когда требуется отформатировать сразу много текста и нужно осуществить контроль использования стекового пространства, дабы избежать переполнения стека.
Примеры: команды /stats (отображение диалогового окна с подробной информацией об аккаунте), /admins, /members (диалог со списком админов или членов банды/мафии/организации онлайн).
Также могут быть команды, из которых вызываются функции, требовательные к стеку ("классика жанра": вызов OnDialogResponse из команды на ZCMD) - тогда следует подсчитывать размеры массивов, если не в самой команде, то в вызываемых функциях.
В остальных случаях подсчёты вряд ли будут стоить временных затрат. Не пытайтесь оптимизировать всё подряд.

Для работ, выкладываемых на форуме, я всё же советую использовать подсчёт, будь то даже простая команда, дабы выставляемый на всеобщее обозрение код был как можно более опрятным.



Ок, теперь, когда со "сферой применения" разобрались, перейдём к примерам. Заодно рассмотрим самые частые быдлокодерские ошибки.
Итак, поехали.

Пример 1:

Допустим, у нас есть команда для вывода ID игрока и его никнейма.
Исходный вид команды:


CMD:myinfo(playerid, params[])
{
new string[128];
new name[24];
GetPlayerName(playerid, name, sizeof(name));
format(string, sizeof(string), "Ваш ID: %d, никнейм: %s.", playerid, name);
return SendClientMessage(playerid, -1, string);
}

Теперь разберём этот код.
Сразу бросается в глаза массив name, вернее его размер "24". Так обычно пишут только быдлокодеры.
Во-первых, размер ника игрока может измениться в будущих версиях SA:MP. В то же время названия констант в новых версиях не меняют. Поэтому, чтобы с выходом новой версии не пришлось по-быдлокодерски заменять все "24" на новые числа, лучше использовать константу.
Во-вторых, с помощью SetPlayerName возможна установка никнейма длиной до 24 (MAX_PLAYER_NAME) символов (см. здесь (http://pro-pawn.ru/showthread.php?12778-GetPlayerName)), а в строке нужна ещё одна позиция для завершающего нуль-символа ('\0'). Отсюда получаем максимум "MAX_PLAYER_NAME + 1".
Пэтому следует переделать объявление массива name следующим образом:

new name[MAX_PLAYER_NAME + 1];

Едем дальше.
Пока мы получаем никнейм игрока в name, массив string никак не используется.
Можно сэкономить место в стеке, получив никнейм сразу в string и затем сформатировать содержимое массива в тот же самый массив:


new string[128];
GetPlayerName(playerid, string, sizeof(string));
format(string, sizeof(string), "Ваш ID: %d, никнейм: %s.", playerid, string);


А теперь самое главное: рассчитаем оптимальный размер массива string.
Начнём с того, что вынесем форматную строку из format в отдельный массив, объявив его с помощью ключевых слов static и const.


static const fmt_str[] = "Ваш ID: %d, никнейм: %s.";
new string[128];
GetPlayerName(playerid, string, sizeof(string));
format(string, sizeof(string), fmt_str, playerid, string);

Теперь составим формулу для расчёта размера массива string.
Сначала возьмём размер массива с форматной строкой: sizeof(fmt_str).
Функция format убирает форматные спецификаторы ("%d", "%i", "%s", etc.) и ставит на их место форматируемые значения.
Поэтому мы в формуле тоже будем убирать длину спецификаторов и прибавлять максимальную длину значений.
В общем виде формула будет выглядеть так:

sizeof(fmt_str)-<длина спецификатора 1>+<макс. длина значения 1>-<длина специф. 2>+<макс. длина знач. 2>-...-<длина специф. N>+<макс. длина знач. N>
Также для удобства можно отделить друг от друга пары "спецификатор-значение", взяв их в скобки:

sizeof(fmt_str) + (-<длина специф. 1>+<макс. длина знач. 1>) + (-<длина специф. 2>+<макс. длина знач. 2>) + ... + (-<длина специф. N>+<макс. длина знач. N>)
Рассчитаем формулу размера string для нашего случая. Сначала идёт спецификатор "%d". Его длина 2 символа, но нужно ещё узнать максимальную длину для целых чисел.
Максимальное целочисленное значение: 2147483647 (10 символов), минимальное: -2147483648 (11 символов), следовательно макс. длина будет 11.
Но следует иметь в виду, что это не просто число, а ID игрока.
На данный момент в SA-MP установлен лимит в 1000 игроков. Максимальный ID - 999 - в текстовом виде занимает 3 символа, однако в будущих версиях это число может перевалить за 1000 из-за увеличения лимита (кто знает?), поэтому я бы советовал не упираться вплотную в текущее ограничение и на всякий случай отводить под ID игрока 4 позиции в строке.
Итак, для подсчёта длины строки, в которой форматируется ID игрока, нужно из sizeof(fmt_str) отнять 2 позиции (длина спецификатора "%d") и прибавить 4.
Дальше идёт "%s", на место этого спецификатора ставится никнейм игрока, максимальная длина которого - MAX_PLAYER_NAME символов (не путать с "MAX_PLAYER_NAME + 1" - в форматированную строку завершающий нуль-символ не попадает, поэтому лишняя ячейка не нужна).
В итоге получаем формулу:

sizeof(fmt_str) + (-2 + 4) + (-2 + MAX_PLAYER_NAME)
Настоятельно рекомендую оформлять формулу расчёта длины именно таким образом, заключая подсчёт для каждого форматного спецификатора в отдельную пару скобок для большей наглядности.

Наконец, подставим полученную формулу в код:


CMD:myinfo(playerid, params[])
{
static const fmt_str[] = "Ваш ID: %d, никнейм: %s.";
new string[sizeof(fmt_str) + (-2 + 4) + (-2 + MAX_PLAYER_NAME)];
GetPlayerName(playerid, string, sizeof(string));
format(string, sizeof(string), fmt_str, playerid, string);
return SendClientMessage(playerid, -1, string);
}




Пример 2:

Немного усложним задачу: кроме ID и никнейма игрока будем выводить его здоровье.
Рассчитаем размер буфера для форматирования. Данный пример похож на предыдущий, просто был добавлен вывод вещ. числа, поэтому можно просто взять размер этого числа, вычесть из предыдущей формулы длину спецификатора "%.0f" и прибавить максимальную длину числа.
Новая форматная строка будет выглядеть так:

static const fmt_str[] = "Ваш ID: %d, никнейм: %s, здоровье: %.0f.";
Функция GetPlayerHealth возвращает вещественные числа от 0 до 255. Если здоровье игрока не находится в этом диапазоне, то функция вычисляет остаток от целочисленного деления здоровья на 256.
При этом дробная часть у возвращаемого здоровья отсутствует, а значит её вместе с запятой можно не выводить.
Исходя из этого, получаем максимальную длину выводимого числа в 3 символа.


CMD:myinfo2(playerid, params[])
{
static const fmt_str[] = "Ваш ID: %d, никнейм: %s, здоровье: %.0f.";
// Обратите внимание: размер спецификатора "%.0f" не 2, а 4 символа.
new string[sizeof(fmt_str) + (-2 + 4) + (-2 + MAX_PLAYER_NAME) + (-4 + 3)];
new Float:health;
GetPlayerName(playerid, string, sizeof(string));
GetPlayerHealth(playerid, health);
format(string, sizeof(string), fmt_str, playerid, string, health);
return SendClientMessage(playerid, -1, string);
}




Пример 3:

Ещё один пример: выведем координаты игрока.
Числа будут выводиться с точностью в 2 знака после запятой.
Длина "%.4f" - 4 символа. Но нужно как-то узнать макс. длину вещественного числа.
Минимальное значение координаты Z: -100 - такое значение возможно, если игрок провалится под текстуру. При высоте меньше -100 его телепортирует обратно на поверхность, так устроен движок GTA:SA.
Максимум Z ограничен максимальным значением, возможным для типа Float, но нам вряд ли понадобятся числа больше или равные 1 000 000, т.к. на больших координатах графика в GTA:SA становится глючной и замедляется процесс отрисовки.
Получаем для координаты Z максимум в 6 символов. При этом спецификатор числа "%.4f" будет занимать 4 символа.
Примерно то же самое с координатами X и Y, только там возможны отрицательные числа меньше -100, а значит наравне с положительными числами могут выводиться отрицательные и следует добавить ещё 1 символ под знак минуса.
В итоге для Z получаем 6 символов, для X и Y - 7 символов. Добавим к этому два знака после запятой и саму запятую и получим 9 и 10 для Z и X/Y соответственно.


CMD:getpos(playerid, params[])
{
static const fmt_str[] = "Ваши координаты: X = %.4f, Y = %.4f, Z = %.4f.";
new string[sizeof(fmt_str) + (-4 + 10) * 2 + (-4 + 9)];
new Float:x, Float:y, Float:z;
GetPlayerPos(playerid, x, y, z);
format(string, sizeof(string), fmt_str, x, y, z);
return SendClientMessage(playerid, -1, string);
}




Пример 4:

И последний пример: выведем ID игрока, никнейм и название машины.
Стандартными средствами SA:MP нельзя узнать название модели транспорта. Тем не менее, можно самостоятельно составить массив названий и брать нужное название по номеру модели транспорта.


// В размере "- 399" означает пропущенные ID от 1 до 399,
// а "+ 1" - самая первая строка, отведённая под 0-ю (несуществующую) модель транспорта.
new const vehicle_model_names[611 - 399 + 1][] =
{
/* 0 */ {!"Нет машины"}, // Для случаев, когда (model == 0), т.е. когда игрок не в машине.
/* 400 */ {!"Landstalker"}, // Также обратите внимание, что строки с названиями упакованные.
/* 401 */ {!"Bravura"},
/* ... */
/* 611 */ {!"Utility Trailer"}
}

stock GetVehicleModelName(model, name, size = sizeof(name))
{
// Если номер модели неизвестен (в т.ч. нулевой)...
if (model < 400 || 611 < model)
return strunpack(name, vehicle_model_names[0], size);
// Модели #400 соответствует название в vehicle_model_names[1], а не [0],
// поэтому следует прибавить 1 к индексу.
return strunpack(name, vehicle_model_names[model - 400 + 1], size);
}

Теперь приступим к составлению формулы длины форматной строки.
Что имеем: ID (в предыдущих примерах обусловились выделять под него 4 позиции), ник (MAX_PLAYER_NAME символов) и название модели транспорта.
Максимальную длину названия транспорта можно определить с помощью выражения "sizeof(vehicle_model_names[]) - 1".
Фигурные скобки после названия массива означают, что мы берём размер его второго измерения, а "- 1" добавлено в конец формулы потому, что для формулы нужно определить длину, а не размер её составляющих.
По той же причине в формуле записывается "MAX_PLAYER_NAME", а не "MAX_PLAYER_NAME + 1". Завершающий нуль-символ уже учтён в "sizeof(fmt_str)".
Получаем следующую формулу:


new fmt_str[] = "Ваш ID: %d, ник: %s, транспорт: %s.";
const string_size = sizeof(fmt_str) + (-2 + 4) +
(-2 + MAX_PLAYER_NAME) + (-2 + sizeof(vehicle_model_names[]);
new string[string_size];

Теперь запишем всю команду целиком:


CMD:myinfo3(playerid, params[])
{
new fmt_str[] = "Ваш ID: %d, ник: %s, транспорт: %s.";
const string_size = sizeof(fmt_str) + (-2 + 4) + (-2 + MAX_PLAYER_NAME) + (-2 + sizeof(vehicle_model_names[]);
new string[string_size];
new name[MAX_PLAYER_NAME + 1], vehicle_name[sizeof(vehicle_model_names[])];
GetPlayerName(playerid, name, sizeof(name));
GetVehicleModelName(GetPlayerVehicleID(playerid), vehicle_name);
format(string, sizeof(string), fmt_str, playerid, name, vehicle_name);
return SendClientMessage(playerid, -1, string);
}

Как и в самом первом примере, переменную name можно убрать, записывая ник прямиком в string.


CMD:myinfo3(playerid, params[])
{
new fmt_str[] = "Ваш ID: %d, ник: %s, транспорт: %s.";
const string_size = sizeof(fmt_str) + (-2 + 4) + (-2 + MAX_PLAYER_NAME) + (-2 + sizeof(vehicle_model_names[]);
new string[string_size];
new vehicle_name[sizeof(vehicle_model_names[])];
GetPlayerName(playerid, string, sizeof(string));
GetVehicleModelName(GetPlayerVehicleID(playerid), vehicle_name);
format(string, sizeof(string), fmt_str, playerid, string, vehicle_name);
return SendClientMessage(playerid, -1, string);
}

Но и это ещё не всё. Переменную vehicle_name тоже можно убрать, а название транспорта записывать - угадайте, куда? Тоже в string, но только не в самое начало массива, а с позиции, на которой закончится ник игрока, т.е. с MAX_PLAYER_NAME + 1.
Места в массиве string должно хватить, т.к. в его размер (string_size) уже входят и длина ника, и длина названия транспорта.


CMD:myinfo3(playerid, params[])
{
new fmt_str[] = "Ваш ID: %d, ник: %s, транспорт: %s.";
const string_size = sizeof(fmt_str) + (-2 + 4) +
(-2 + MAX_PLAYER_NAME) + (-2 + sizeof(vehicle_models_names[]);
new string[string_size];
GetPlayerName(playerid, string, sizeof(string));
GetVehicleModelName(GetPlayerVehicleID(playerid), string[MAX_PLAYER_NAME + 1]);
format(
string, sizeof(string), fmt_str,
playerid, string, string[MAX_PLAYER_NAME + 1]
);
return SendClientMessage(playerid, -1, string);
}




Вот так в Pawn можно грамотно рассчитать размер форматируемой строки. Впрочем, приведённые выше правила действуют и в других языках программирования, если не брать в расчёт особенности синтаксиса.
Если этот урок показался вам неполным и вы хотите что-то добавить или спросить - рад буду выслушать вас в комментариях.


Автор: Daniel_Cortez (http://pro-pawn.ru/member.php?100-Daniel_Cortez)


Специально для Pro-Pawn.ru (http://www.pro-pawn.ru)
Копирование данной статьи на других ресурсах без разрешения автора запрещено!

Desulaid
07.02.2016, 18:34
Еще упомяни, что в "\n, \t, ..." и т.д - это один символ. :good2:

Profyan
07.02.2016, 18:34
Сколько в среднем у вас занимает времени расчет строки?

Daniel_Cortez
07.02.2016, 18:49
Сколько в среднем у вас занимает времени расчет строки?
На первый пример из урока у меня ушло ~40 секунд, с учётом времени ввода форматной строки и объявления форматного буфера с формулой расчёта. А так всё это больше зависит от сложности алгоритма, для которого нужно провести подсчёт.



Еще упомяни, что в "\n, \t, ..." и т.д - это один символ. :good2:
Напишу об этом чуть позже, как только добавлю ещё один пример с диалогом.

$continue$
07.02.2016, 20:42
Опечатка?


static const fmt_str[] = "Ваш ID: %d, никнейм: %s, здоровье: %.0f.";
// Обратите внимание: размер спецификатора "%.0f" на 2, а 4 символа.

_lizard
26.02.2016, 21:55
A как быть, если нужно два и более раза отформатировать массив?

VVWVV
26.02.2016, 22:21
A как быть, если нужно два и более раза отформатировать массив?


static const
fmt_str_0[] = "something %s",
fmt_str_1[] = "something %d";

const
fmt_str_0_size = sizeof fmt_str_0 + (-2 + MAX_PLAYER_NAME),
fmt_str_1_size = sizeof fmt_str_1 + (-2 + 4);

#if fmt_str_0_size > fmt_str_1_size
#define size fmt_str_0_size
// Либо const size = fmt_str_0_size;
#else
#define size fmt_str_1_size
// Либо const size = fmt_str_1_size;
#endif
new buffer[size];

// Если используете const, то данная директива не нужна.
#undef size

_lizard
26.02.2016, 22:51
new buffer[size];

Мм, немного не догнал, зачем создавать третий массив, если можно использовать два первых?

VVWVV
26.02.2016, 23:02
Мм, немного не догнал, зачем создавать третий массив, если можно использовать два первых?

Данный массив создан для того, чтобы поместить в него уже отформатированный текст (например, с помощью функции format). С помощью препроцессора мы выбираем самую длинную строку, после чего записываем в макрос, который в дальнейшем будет размером массива (точнее, то, что он подставит вместо себя). Если говорить о двух первых строках, то они сохраняются в сегменте данных.

Daniel_Cortez
27.02.2016, 06:59
static const
fmt_str_0[] = "something %s",
fmt_str_1[] = "something %d";

const
fmt_str_0_size = sizeof fmt_str_0 + (-2 + MAX_PLAYER_NAME),
fmt_str_1_size = sizeof fmt_str_1 + (-2 + 4);

#if fmt_str_0_size > fmt_str_1_size
#define size fmt_str_0_size
#else
#define size fmt_str_1_size
#endif
new buffer[size];
"#undef size" забыл. А вообще можно было объявить константу (const) вместо макроса.

stimorol
27.03.2016, 18:40
DC, здравствуйте.

Вот элементарная загрузка аккаунта:



GetPlayerName(playerid, PlayerInfo[playerid][pName], MAX_PLAYER_NAME);
static fmt_str[] = "SELECT * FROM `accounts` WHERE `Name` = '%s'";
new query_string[sizeof(fmt_str)-2+MAX_PLAYER_NAME+1];
format(query_string, sizeof(query_string), fmt_str, PlayerInfo[playerid][pName]);
mysql_function_query(mysql_connect_id, query_string, true, "CheckRegisterPlayer", "i", playerid);


Как вы могли заметить в подсчёте я указал MAX_PLAYER_NAME+1, вот и вопрос. В каких случаях пишется просто MAX_PLAYER_NAME, а в каких MAX_PLAYER_NAME+1?

VVWVV
27.03.2016, 19:09
DC, здравствуйте.

Вот элементарная загрузка аккаунта:



GetPlayerName(playerid, PlayerInfo[playerid][pName], MAX_PLAYER_NAME);
static fmt_str[] = "SELECT * FROM `accounts` WHERE `Name` = '%s'";
new query_string[sizeof(fmt_str)-2+MAX_PLAYER_NAME+1];
format(query_string, sizeof(query_string), fmt_str, PlayerInfo[playerid][pName]);
mysql_function_query(mysql_connect_id, query_string, true, "CheckRegisterPlayer", "i", playerid);


Как вы могли заметить в подсчёте я указал MAX_PLAYER_NAME+1, вот и вопрос. В каких случаях пишется просто MAX_PLAYER_NAME, а в каких MAX_PLAYER_NAME+1?

MAX_PLAYER_NAME не причём, т.к. к общему размеру массива прибавляем плюс 1 (т.е. ещё одну ячейку) для нулевого символа (нужен для того, чтобы разъединять строки в памяти).

DeimoS
27.03.2016, 22:56
DC, здравствуйте.

Вот элементарная загрузка аккаунта:



GetPlayerName(playerid, PlayerInfo[playerid][pName], MAX_PLAYER_NAME);
static fmt_str[] = "SELECT * FROM `accounts` WHERE `Name` = '%s'";
new query_string[sizeof(fmt_str)-2+MAX_PLAYER_NAME+1];
format(query_string, sizeof(query_string), fmt_str, PlayerInfo[playerid][pName]);
mysql_function_query(mysql_connect_id, query_string, true, "CheckRegisterPlayer", "i", playerid);


Как вы могли заметить в подсчёте я указал MAX_PLAYER_NAME+1, вот и вопрос. В каких случаях пишется просто MAX_PLAYER_NAME, а в каких MAX_PLAYER_NAME+1?

Только не стоит забывать, что игрок при входе может ввести только ник длинною в 20 символов (MAX_PLAYER_NAME является числом "24", где 20 символов под ник для игрока и ещё 4 символа для того, чтоб изменить ник со стороны сервера, добавив какой-то префикс (например, "AFK") даже если у игрока ник равен 20 символам). Следовательно, выделять "MAX_PLAYER_NAME+1" имеет смысл только тогда, когда в твоём моде присутствует код смены ника с добавлением какого-либо префикса (то бишь, ник игрока может быть больше 20 символов только благодаря SetPlayerName => если SetPlayerName вообще не используется, либо ты сразу делаешь проверку на то, что новый ник не больше 20 символов, то и выделять 25 ячеек бессмысленно). Во всех остальных случаях достаточно выделить "MAX_PLAYER_NAME-3" или же "MAX_PLAYER_NAME-4+1" (-4 ячейки, которые выделены для ника с сервера и + 1 ячейка для нуль-символа). А лучше сделать какой-то свой макрос, где уже указывать число, которому равно число символов для нужды сервера (те самые 4 символа), ибо вполне возможно, что в будущем это число может измениться разработчиками и тогда придётся перелопачивать весь мод вручную.
P.S. Заранее прошу прощения, если где-то повторяюсь. Немного плыву и трудно сформулировать мысль :с

stimorol
28.03.2016, 12:21
И ещё один вопрос. В каких случаях используется static const, а в каких просто static?

BadPawn
28.03.2016, 17:42
http://pro-pawn.ru/showthread.php?7762-Что-лучше-new-или-static

Daniel_Cortez
28.03.2016, 21:17
Добавил пример #4, в котором показано форматирование с 2 и более строковыми аргументами.




MAX_PLAYER_NAME не причём, т.к. к общему размеру массива прибавляем плюс 1 (т.е. ещё одну ячейку) для нулевого символа (нужен для того, чтобы разъединять строки в памяти).
Наиболее точной здесь будет формулировка "для обозначения окончания строки".



Только не стоит забывать, что игрок при входе может ввести только ник длинною в 20 символов (MAX_PLAYER_NAME является числом "24", где 20 символов под ник для игрока и ещё 4 символа для того, чтоб изменить ник со стороны сервера, добавив какой-то префикс (например, "AFK") даже если у игрока ник равен 20 символам). Следовательно, выделять "MAX_PLAYER_NAME+1" имеет смысл только тогда, когда в твоём моде присутствует код смены ника с добавлением какого-либо префикса (то бишь, ник игрока может быть больше 20 символов только благодаря SetPlayerName => если SetPlayerName вообще не используется, либо ты сразу делаешь проверку на то, что новый ник не больше 20 символов, то и выделять 25 ячеек бессмысленно). Во всех остальных случаях достаточно выделить "MAX_PLAYER_NAME-3" или же "MAX_PLAYER_NAME-4+1" (-4 ячейки, которые выделены для ника с сервера и + 1 ячейка для нуль-символа). А лучше сделать какой-то свой макрос, где уже указывать число, которому равно число символов для нужды сервера (те самые 4 символа), ибо вполне возможно, что в будущем это число может измениться разработчиками и тогда придётся перелопачивать весь мод вручную.
P.S. Заранее прошу прощения, если где-то повторяюсь. Немного плыву и трудно сформулировать мысль :с
Это недокументированное свойство и для того значения даже нет константы. Мало того, нет даже гарантии, что оно изменится вместе с MAX_PLAYER_NAME в будущей версии SA:MP.
По сути то, что ты предлагаешь - точно такое же зло, как использовать 24 вместо MAX_PLAYER_NAME: всё будет работать, но только до поры, до времени.



DC, здравствуйте.

Вот элементарная загрузка аккаунта:



GetPlayerName(playerid, PlayerInfo[playerid][pName], MAX_PLAYER_NAME);
static fmt_str[] = "SELECT * FROM `accounts` WHERE `Name` = '%s'";
new query_string[sizeof(fmt_str)-2+MAX_PLAYER_NAME+1];
format(query_string, sizeof(query_string), fmt_str, PlayerInfo[playerid][pName]);
mysql_function_query(mysql_connect_id, query_string, true, "CheckRegisterPlayer", "i", playerid);


Как вы могли заметить в подсчёте я указал MAX_PLAYER_NAME+1, вот и вопрос. В каких случаях пишется просто MAX_PLAYER_NAME, а в каких MAX_PLAYER_NAME+1?
Проверьте 4-й пример, там этот вопрос разжёван.

DeimoS
29.03.2016, 12:19
Это недокументированное свойство и для того значения даже нет константы.

Так я и предлагаю её создать самостоятельно, дабы, в случае изменений со стороны мультиплеера, внести всего 1 изменение.



Мало того, нет даже гарантии, что оно изменится вместе с MAX_PLAYER_NAME в будущей версии SA:MP.

Как и нет гарантий того, что оно не изменится.


По сути то, что ты предлагаешь - точно такое же зло, как использовать 24 вместо MAX_PLAYER_NAME: всё будет работать, но только до поры, до времени.

Почему же? Как я уже сказал и выше, и в том сообщении - под такое значение можно объявить константу и, при любых изменениях со стороны клиента, вносить изменения в эту константу

VVWVV
29.03.2016, 16:02
Так я и предлагаю её создать самостоятельно, дабы, в случае изменений со стороны мультиплеера, внести всего 1 изменение.

Как и нет гарантий того, что оно не изменится.

Почему же? Как я уже сказал и выше, и в том сообщении - под такое значение можно объявить константу и, при любых изменениях со стороны клиента, вносить изменения в эту константу

Можно, но тем не менее, придётся добавлять большое количество констант с проверками, дабы узнать об изменении и обновлении версии. Также есть доля вероятности, что последние 4 ячейки все-таки будут заняты какими-то значениями, и вы получите выход за пределы массива (только в некоторых случаях). А также вы можете просто забыть про данную константу (например, не ввести новое значение).

DeimoS
29.03.2016, 16:42
Можно, но тем не менее, придётся добавлять большое количество констант с проверками, дабы узнать об изменении и обновлении версии.
Не думаю, что Куй вдруг изменит макрос MAX_PLAYER_NAME и не сообщит об этом. Да и "большое кол-во проверок" будет выглядеть так, если я правильно тебя понял:

#if MAX_PLAYER_NAME != 24
#error Macro MAX_PLAYER_NAME is not equal to 24
#endif


Также есть доля вероятности, что последние 4 ячейки все-таки будут заняты какими-то значениями, и вы получите выход за пределы массива (только в некоторых случаях).
Если все действия над ником совершать с учётом того, что ник равен не больше 20 символов, то никак не может получится выход за пределы массива. Если уж это случится - виной всему кривые руки скриптера, а не предложенный мною вариант (ну или тогда давайте всю вину за все случаи самоубийства, связанные с оружием, переложим на производителей этого оружия, а не на тех идиотов, кто совершил самоубийство)


А также вы можете просто забыть про данную константу (например, не ввести новое значение).

Опять же, это чисто человеческий фактор и точно так же можно сказать про эту тему с подсчётом: вы можете просто неправильно составить формулу для подсчёта числа символов и выделите больше/меньше нужного.

VVWVV
29.03.2016, 16:53
Не думаю, что Куй вдруг изменит макрос MAX_PLAYER_NAME и не сообщит об этом. Да и "большое кол-во проверок" будет выглядеть так, если я правильно тебя понял:

#if MAX_PLAYER_NAME != 24
#error Macro MAX_PLAYER_NAME is not equal to 24
#endif


Если все действия над ником совершать с учётом того, что ник равен не больше 20 символов, то никак не может получится выход за пределы массива. Если уж это случится - виной всему кривые руки скриптера, а не предложенный мною вариант (ну или тогда давайте всю вину за все случаи самоубийства, связанные с оружием, переложим на производителей этого оружия, а не на тех идиотов, кто совершил самоубийство)



Опять же, это чисто человеческий фактор и точно так же можно сказать про эту тему с подсчётом: вы можете просто неправильно составить формулу для подсчёта числа символов и выделите больше/меньше нужного.

Хотя да, всему виной могут послужить "кривые" руки скриптера.
Для большего удобства лучше сделать так:


#define SUB_MAX_PLAYER_NAME (4)
#define C_MAX_PLAYER_NAME (MAX_PLAYER_NAME - SUB_MAX_PLAYER_NAME)
#assert ((C_MAX_PLAYER_NAME + SUM_MAX_PLAYER_NAME) == MAX_PLAYER_NAME)

DeimoS
29.03.2016, 17:44
Хотя да, всему виной могут послужить "кривые" руки скриптера.
Для большего удобства лучше сделать так:


#define SUB_MAX_PLAYER_NAME (4)
#define C_MAX_PLAYER_NAME (MAX_PLAYER_NAME - SUB_MAX_PLAYER_NAME)
#assert ((C_MAX_PLAYER_NAME + SUM_MAX_PLAYER_NAME) == MAX_PLAYER_NAME)

Если уж наверняка уверен, что не будешь использовать нигде добавление префикса к нику игрока, можно просто

#if MAX_PLAYER_NAME != 24
#error Macro MAX_PLAYER_NAME is not equal to 24
#endif
#undef MAX_PLAYER_NAME
#define MAX_PLAYER_NAME 21//Под нуль-символ ещё же
И всё.

P.S. А при смене ника вы и так должны 100% ограничивать игрока длиной в 20 символов, ибо если он введёт хотя бы 21 символ и вы запишете это в аккаунт, он уже не сможет зайти за свой аккаунт, ибо сам клиент не пустит его на сервер :3

Daniel_Cortez
30.03.2016, 16:42
Почему же? Как я уже сказал и выше, и в том сообщении - под такое значение можно объявить константу и, при любых изменениях со стороны клиента, вносить изменения в эту константу
Потому, что это лишняя задача, которую ты предлагаешь добровольно взвалить на свои плечи, причём задача долгосрочная, если учесть скорость выхода обновлений SA:MP.
И, как уже ответил выше VVWVV, не факт, что вспомните о такой мелочи после обновления.
Можно ещё сделать напоминание, добавив рядом с константой директивы для вывода сообщения об ошибке (#if, #error) при использовании новых версий SA:MP. Но как определить сам факт обновления? В стандартных инклудах нет ни одной константы, которая отвечала бы за номер версии.



Не думаю, что Куй вдруг изменит макрос MAX_PLAYER_NAME и не сообщит об этом. Да и "большое кол-во проверок" будет выглядеть так, если я правильно тебя понял:

#if MAX_PLAYER_NAME != 24
#error Macro MAX_PLAYER_NAME is not equal to 24
#endif

Хотя да, всему виной могут послужить "кривые" руки скриптера.
Для большего удобства лучше сделать так:


#define SUB_MAX_PLAYER_NAME (4)
#define C_MAX_PLAYER_NAME (MAX_PLAYER_NAME - SUB_MAX_PLAYER_NAME)
#assert ((C_MAX_PLAYER_NAME + SUM_MAX_PLAYER_NAME) == MAX_PLAYER_NAME)
Уже ближе к истине, но опять же, те два значения могут не зависеть друг от друга. Может возникнуть такая ситуация, что лимит ника в клиенте увеличится (например, станет 24 вместо 20), а значение MAX_PLAYER_NAME останется прежним.
Не вы создаёте клиент и не вам придумывать те константы.

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

DeimoS
30.03.2016, 17:13
Потому, что это лишняя задача, которую ты предлагаешь добровольно взвалить на свои плечи, причём задача долгосрочная, если учесть скорость выхода обновлений SA:MP.

Ну тогда давай и MAX_PLAYERS оставлять на 1000 даже если у нас всего 50 слотов на сервере. Ведь вдруг Куй вдруг решит сделать максимум 49 слотов и не предупредит нас... -_-



И, как уже ответил выше VVWVV, не факт, что вспомните о такой мелочи после обновления.

Ну это уже исключительно твои проблемы и проблемы твоей профпригодности. Сервер в SA-MP - не плагин или программа, которую ты выпустил раз, пару раз пофиксил и забыл о ней. Если ты действительно держишь сервер, ты постоянно над ним работаешь и вряд ли ты о таком забудешь, если вдруг выйдет новая версия.

Да и кто вообще обновляет свой сервер, при этом не ознакамливаясь со всеми нововведениями? Не думаю, что такие есть, как минимум, в связи с тем, что эти обновления выходят раз в год и ты тупо из любопытства поинтересуешься.
А кто хоть раз обновлял свой сервер до новой версии (особенно в день релиза), те знают, что в такие моменты за сервером следует следить особенно сильно, ибо Куй. И даже если вдруг обнаружится, что этот самый Куй не сообщил о изменении ограничений ника, то:
Во-первых, ты всё быстро сможешь изменить, просто подправив значения и скомпилировав мод.
Во-вторых, ничего страшного не случится (Максимум, у кого-то, кто вдруг решит ввести себе длинный ник, этот самый ник будет отображаться/сохранится неверно и прочее).


Уже ближе к истине, но опять же, те два значения могут не зависеть друг от друга. Может возникнуть такая ситуация, что лимит ника в клиенте увеличится (например, станет 24 вместо 20), а значение MAX_PLAYER_NAME останется прежним.
Не вы создаёте клиент и не вам придумывать те константы.

Ну тогда и стандартная константа станет точно такой же непригодной, как и исправленная. И "последствия" от использования её будут точно такие же.
Да и если вдруг Куй сделает что-то подобное, проблем всё равно не избежать, ибо у пользователей MySQL столбец с длиной ника в любом случае будет равен 24 символам и все новые аккаунты длиннее 24 символов просто не запишет (даже без использования изменённой константы)


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

99% (данные с потолка, ога) тех, кто держит сервера и сидит на форумах, подобных этому, дальше SA-MP не уйдут никогда. А те, кто уйдёт, изначально должны понимать, что подобная практика не всегда хороша и накладывает на тебя кучу ответственности. Как бы ты не пытался продвинуть тут "правильный" стиль кодинга, те люди, что не включают голову при написании кода, всё равно обожгуться: не на этих константах, так на чём-то ещё. И пока они не обожгутся, они не поймут всех тонкостей

Daniel_Cortez
30.03.2016, 18:28
Ну тогда давай и MAX_PLAYER_NAME оставлять на 1000 даже если у нас всего 50 слотов на сервере. Ведь вдруг Куй вдруг решит сделать максимум 49 слотов и не предупредит нас... -_-
Ты, наверное, хотел сказать про MAX_PLAYERS? Сомневаюсь, что куй пойдёт на такую глупость, хотя увеличить лимит он рано или поздно может.



Ну это уже исключительно твои проблемы и проблемы твоей профпригодности. Сервер в SA-MP - не плагин или программа, которую ты выпустил раз, пару раз пофиксил и забыл о ней. Если ты действительно держишь сервер, ты постоянно над ним работаешь и вряд ли ты о таком забудешь, если вдруг выйдет новая версия.
Тем не менее, хорошим тоном обычно считается минимизация всех подобных мелочей и грязных хаков, которые программисту следует запоминать. Зачем усложнять себе жизнь лишними деталями о проекте?
Мало того, если ты уйдёшь с поста разработчика в каком-нибудь проекте и на твоё место придёт новый человек, он потеряет уйму времени на изучение всех тех хаков, которые ты оставил ему "в наследство".



Да и кто вообще обновляет свой сервер, при этом не ознакамливаясь со всеми нововведениями? Не думаю, что такие есть, как минимум, в связи с тем, что эти обновления выходят раз в год и ты тупо из любопытства поинтересуешься.
Не факт, что об этом будет сказано в описании к обновлению. Во-первых, это будет сравнительно небольшое изменение. Во-вторых, как следствие первого, о таком изменении легко забыть.



И даже если вдруг обнаружится, что этот самый Куй не сообщил о изменении ограничений ника, то:
Во-первых, ты всё быстро сможешь изменить, просто подправив значения и скомпилировав мод.
Во-вторых, ничего страшного не случится (Максимум, у кого-то, кто вдруг решит ввести себе длинный ник, этот самый ник будет отображаться/сохранится неверно и прочее).
Представим такую ситуацию: на сервере есть игрок с ником Alexander_Nikolaenko (20 символов) и в его собственности на сервере есть дом, машина, небольшая яхта и счёт в банке.
Проверка владельца осуществляется следующим образом:


new name[20 + 1];
GetPlayerName(playerid, name, sizeof(name));
if (strcmp(name, HouseInfo[houseid][hOwnerName], false, 20))
return SendClientMessage(playerid, -1, "You shall not pass!");
// ok

И если зарегистрироваться под ником Alexander_Nikolaenko123, то последние 3 символа проверены не будут и сервер подумает, что это и есть владелец собствнности.
Так можно украсть не только серверную собственность, но и кое-что посерьёзнее - админку, например, а там последствия ограничиваются лишь фантазией злоумышленника.
Но попробуй сначала узнай, как именно взломщик обошёл все проверки! Ты же не будешь знать об изменении незадокументированной константы заранее.
Да, по нику Alexander_Nikolaenko123 можно догадаться, но не сразу найдёшь уязвимый отрывок кода, да и не факт, что вообще поймёшь, в чём дело.
И это только один пример вектора атаки.



Ну тогда и стандартная константа станет точно такой же непригодной, как и исправленная. И "последствия" от использования её будут точно такие же.
Просто перекомпилируй сервер с новой версией стандартных инклудов, в которых значение MAX_PLAYER_NAME увеличится, и если ты везде пользуешься именно этой константой, а не втыкаешь "24" на скорую руку, то всё будет нормально.



Да и если вдруг Куй сделает что-то подобное, проблем всё равно не избежать, ибо у пользователей MySQL столбец с длиной ника в любом случае будет равен 24 символам и все новые аккаунты длиннее 24 символов просто не запишет (даже без использования изменённой константы)
Это уже проблема не самого кода на Pawn, а СУБД, в которой используется совершенно другой ЯП. Как вариант, можно установить длину ника в 24 символа и увеличивать её в момент изменения MAX_PLAYER_NAME - уж об изменении стандартной константы должны будут объявить при выходе обновления.



99% (данные с потолка, ога) тех, кто держит сервера и сидит на форумах, подобных этому, дальше SA-MP не уйдут никогда. А те, кто уйдёт, изначально должны понимать, что подобная практика не всегда хороша и накладывает на тебя кучу ответственности. Как бы ты не пытался продвинуть тут "правильный" стиль кодинга, те люди, что не включают голову при написании кода, всё равно обожгуться: не на этих константах, так на чём-то ещё.
Во-первых, мои посты и не предназначены для владельцев серверов-однодневок.
Во-вторых, твои "99%" не означают, что следует учить плохим практикам и оставшийся 1%. По твоей логике можно вообще отменить все требования к стандартам кодинга и закрыть pro-pawn к чертям собачьим, а пользователей отправить набирать знания на govno-info.



И пока они не обожгутся, они не поймут всех тонкостей
Что самое интересное, многие могут даже не понять, обо что обожглись. А если начнёшь объяснять, будут упорно это что-то защищать или пытаться избегать разговора. Впрочем, не то чтобы ты _должен_ им что-то объяснять...
Естественно, для такие людей этот форум не предназначен.

DeimoS
30.03.2016, 19:15
Ты, наверное, хотел сказать про MAX_PLAYERS? Сомневаюсь, что куй пойдёт на такую глупость, хотя увеличить лимит он рано или поздно может.

Да, именно о MAX_PLAYERS, прошу прощения.


Тем не менее, хорошим тоном обычно считается минимизация всех подобных мелочей и грязных хаков, которые программисту следует запоминать. Зачем усложнять себе жизнь лишними деталями о проекте?
Мало того, если ты уйдёшь с поста разработчика в каком-нибудь проекте и на твоё место придёт новый человек, он потеряет уйму времени на изучение всех тех хаков, которые ты оставил ему "в наследство".

Ну тогда говорю же, давай вообще откажемся от любых изменений стандартных макросов, в том числе и MAX_PLAYERS. Ведь вдруг в проект придёт кто-то ещё...
Ну или укажи мне на ту самую грань, когда изменение стандартных макросов ещё приемлемо и когда уже не приемлемо.

Да и обычно в случаях, когда есть шанс передачи проекта другому человеку, принято оставлять комментарии к своему коду, не? В которых и указывать все подобные хаки.


Не факт, что об этом будет сказано в описании к обновлению. Во-первых, это будет сравнительно небольшое изменение. Во-вторых, как следствие первого, о таком изменении легко забыть.
Сравнительно небольшое изменение, которое фактически логику всего мода изменяет...




Представим такую ситуацию: на сервере есть игрок с ником Alexander_Nikolaenko (20 символов) и в его собственности на сервере есть дом, машина, небольшая яхта и счёт в банке.
Проверка владельца осуществляется следующим образом:


new name[20 + 1];
GetPlayerName(playerid, name, sizeof(name));
if (strcmp(name, HouseInfo[houseid][hOwnerName], false, 20))
return SendClientMessage(playerid, -1, "You shall not pass!");
// ok

И если зарегистрироваться под ником Alexander_Nikolaenko123, то последние 3 символа проверены не будут и сервер подумает, что это и есть владелец собствнности.
Так можно украсть не только серверную собственность, но и кое-что посерьёзнее - админку, например, а там последствия ограничиваются лишь фантазией злоумышленника.
Но попробуй сначала узнай, как именно взломщик обошёл все проверки! Ты же не будешь знать об изменении незадокументированной константы заранее.
Да, по нику Alexander_Nikolaenko123 можно догадаться, но не сразу найдёшь уязвимый отрывок кода, да и не факт, что вообще поймёшь, в чём дело.
И это только один пример вектора атаки.

Если такое случится, то игрока ещё на стадии авторизации опознает как Alexander_Nikolaenko и предложит ему именно авторизироваться, а не зарегистрироваться.


Просто перекомпилируй сервер с новой версией стандартных инклудов, в которых значение MAX_PLAYER_NAME увеличится, и если ты везде пользуешься именно этой константой, а не втыкаешь "24" на скорую руку, то всё будет нормально.
Так мы же говорим о ситуации, когда Куй забыл изменить макрос MAX_PLAYER_NAME и оставил его равным 24, хотя в самом клиенте изменения внёс, не? Если брать обратную ситуацию, то, опять же, я дал условие, которое сразу сообщит о изменении значения макроса



Это уже проблема не самого кода на Pawn, а СУБД, в которой используется совершенно другой ЯП. Как вариант, можно установить длину ника в 24 символа и увеличивать её в момент изменения MAX_PLAYERS

Я знаю чья это проблема, но проблема от этого не перестаёт быть реальной.


уж об изменении стандартной константы должны будут объявить при выходе обновления.


Может возникнуть такая ситуация, что лимит ника в клиенте увеличится (например, станет 24 вместо 20), а значение MAX_PLAYER_NAME останется прежним.


Во-первых, мои посты и не предназначены для владельцев серверов-однодневок.

Ну ты можешь упорно пытаться закрывать глаза на реальность, но от этого она не изменится - сервера в SA-MP для многих являются как хобби и не более. Так же, как и в других играх, кои сервера тогда тоже можно назвать "однодневками" (в тот же DayZ или CS зайди и процентов 60 всех серверов будут являться обычными сборками, установленными на сервер и владельцы этих серверов не смогут сами даже какой-то новый плагин подключить без мануала).


Во-вторых, твои "99%" не означают, что следует учить плохим практикам и оставшийся 1%. По твоей логике можно вообще отменить все требования к стандартам кодинга и закрыть pro-pawn к чертям собачьим, а пользователей отправить набирать знания на govno-info.

По моей логике не нужно иметь двойных стандартов и продвигать только те хаки, которые именно тебе кажутся удобными, а все остальные гнобить :3




Что самое интересное, многие могут даже не понять, обо что обожглись.

Потому что их изначально учат тому, что не нужно думать, нужно просто делать как говорят! И в садике так учат, и в школе так учат, и на форуме так же учат: "вот так делать правильно и не смей пробовать иначе, ибо плохо будет! Как именно плохо? Не важно, делай как говорят!"


А если начнёшь объяснять, будут упорно это что-то защищать или пытаться избегать разговора. Впрочем, не то чтобы ты _должен_ им что-то объяснять...

Вот ты мне писал, мол зачем я сижу на p-i. Но не поверишь, если людям с того форума попытаться начать НОРМАЛЬНО объяснять, раскладывая всё по полочкам, большая часть из них (где-то четыре к двум) начинает понимать о чём идёт речь и начинают интересоваться Pawn в правильном направлении. Есть даже те, кого я звал на этот форум и кто тут даже остался
Печаль в том, что многие на этом форуме настолько возомнили себя особенными, что начинают гнобить (именно гнобить, а не подсказывать и помогать) тем, кто приходит с того же p-i и начинает по привычке заливать сюда всякий шлак. Люди уже настолько заигрались во вражду форумов (которая, кстати, идёт только в одностороннем порядке: от p-p к p-i), что не замечают когда перегибают палку (если кто-то более-менее знаменитый на p-i заходит сюда и делает хоть одну маленькую ошибку в своём коде, либо просто не соблюдает общепринятый тут стиль написания кода, его открыто начинают слать на p-i и говорить, что тут такие не нужны... В общем, страшненько это
В общем, далеко не все такие упёртые, как ты сейчас пытаешься сказать. Просто есть те, кто заперт в том мире, что создал p-i со своим говнокодом, ибо когда люди гуглят о чём-либо для SA-MP, чаще всего им попадается именно этот крупный портал и они просто не знают, что на p-p информация качественнее. И твоя позиция "говнокодеры этому порталу не нужны" никак не исправит ситуацию, ибо для того, чтоб говнокодер понял о том, что он говнокодер, ты должен ему это объяснить на понятных для него примерах. Тогда он и не будет на всеми тут ненавистном p-i сидеть. Хотя право твоё



Естественно, для такие людей этот форум не предназначен.

Именно поэтому этот форум и находится в стагнации :с

Daniel_Cortez
30.03.2016, 20:08
Ну тогда говорю же, давай вообще откажемся от любых изменений стандартных макросов, в том числе и MAX_PLAYERS. Ведь вдруг в проект придёт кто-то ещё...
Ну или укажи мне на ту самую грань, когда изменение стандартных макросов ещё приемлемо и когда уже не приемлемо.
Я вообще ничего не говорил про изменение макросов. И, раз уж на то пошло, значение MAX_PLAYER_NAME, как и MAX_PLAYERS можно уменьшить, в функции GetPlayerName всё равно указывается размер буфера. Тем не менее, следует задуматься о возможных последствиях и осознавать риск вмешательства в стандартные константы.
Если при изменении MAX_PLAYERS будет только вероятность выхода за пределы массива, если в server.cfg указано больше слотов, то при уменьшении MAX_PLAYER_NAME можно получить и что-нибудь похуже.
Мало того, MAX_PLAYERS обычно переобъявляют, чтобы сэкономить память, но какой может быть смысл вмешиваться в MAX_PLAYER_NAME, если там можно сэкономить от силы несколько ячеек?



Да и обычно в случаях, когда есть шанс передачи проекта другому человеку, принято оставлять комментарии к своему коду, не? В которых и указывать все подобные хаки.
Тем не менее, на ознакомление с этими хаками всё равно уйдёт время, с комментариями или без.



Сравнительно небольшое изменение, которое фактически логику всего мода изменяет...
Ты мыслишь, как скриптер, а следовало бы мыслить как разработчик SA:MP. Тот самый разработчик, которому плевать на скриптеров и на всю аудиторию в целом (за исключением денег, естественно).
Если бы он думал о логике, он бы давно уже сделал соответствие макс. длины ника в клиенте значению MAX_PLAYER_NAME. Но воз и ныне там...
И да, раньше уже были случаи с недокументированными изменениями. Вот пример одного из них в 0.3.7:



Со скинов 165 и 166 удалены солнцезащитные очки.





Если такое случится, то игрока ещё на стадии авторизации опознает как Alexander_Nikolaenko и предложит ему именно авторизироваться, а не зарегистрироваться.
А может быть такая ошибка закралась только в код проверки домов/машин/админки? Они же не зависят друг от друга.



Так мы же говорим о ситуации, когда Куй забыл изменить макрос MAX_PLAYER_NAME и оставил его равным 24, хотя в самом клиенте изменения внёс, не? Если брать обратную ситуацию, то, опять же, я дал условие, которое сразу сообщит о изменении значения макроса
С помощью SetPlayerName можно установить ник не до 20, а до 24 символов, т.е. до MAX_PLAYER_NAME.



Я знаю чья это проблема, но проблема от этого не перестаёт быть реальной.
Тем не менее, возможное решение я привёл.



Ты сам себе противоречишь -_-
Может, посвятишь меня, в чём именно?



Ну ты можешь упорно пытаться закрывать глаза на реальность, но от этого она не изменится - сервера в SA-MP для многих являются как хобби и не более.
Я это прекрасно понимаю. Более того, я и не рассчитываю что-то заметно изменить.



По моей логике не нужно иметь двойных стандартов и продвигать только те хаки, которые именно тебе кажутся удобными, а все остальные гнобить :3
Хаки, которые "кажутся мне удобными"? Например?



Потому что их изначально учат тому, что не нужно думать, нужно просто делать как говорят! И в садике так учат, и в школе так учат, и на форуме так же учат: "вот так делать правильно и не смей пробовать иначе, ибо плохо будет! Как именно плохо? Не важно, делай как говорят!"
И что ты хочешь этим сказать?



И твоя позиция "говнокодеры этому порталу не нужны"
Речь была о тех, кто не способен обучаться.



Именно поэтому этот форум и находится в стагнации
Уж лучше так, чем ещё один г-и. И да, ещё раз ответ выше.

DeimoS
30.03.2016, 21:35
Я вообще ничего не говорил про изменение макросов.

А разве не об этом изначально была речь?...


И, раз уж на то пошло, значение MAX_PLAYER_NAME, как и MAX_PLAYERS можно уменьшить, в функции GetPlayerName всё равно указывается размер буфера. Тем не менее, следует задуматься о возможных последствиях и осознавать риск вмешательства в стандартные константы.

Я уже раза 3 сказал о том, что подобные махинации с кодом влекут за собой соответствующие последствия...



Если при изменении MAX_PLAYERS будет только вероятность выхода за пределы массива, если в server.cfg указано больше слотов, то при уменьшении MAX_PLAYER_NAME можно получить и что-нибудь похуже.

Например?


Мало того, MAX_PLAYERS обычно переобъявляют, чтобы сэкономить память, но какой может быть смысл вмешиваться в MAX_PLAYER_NAME, если там можно сэкономить от силы несколько ячеек?

Несколько ячеек в случае с GetPlayerName в OnPlayerConnect + несколько ячеек в случае с массивом для хранения приветствия при входе + ещё несколько ячеек при запросе в бд... Данный макрос используется часто и "несколько ячеек" могут превратиться в пару сотен. Да и, опять же, хочется вспомнить политику двойных стандартов, когда в одном случае изобретать велосипеды - нормально, а в другом - греху подобно. КОгда это экономия лишней пары ячеек стала чем-то плохим?


Тем не менее, на ознакомление с этими хаками всё равно уйдёт время, с комментариями или без.
Как и на ознакомление с остальным кодом, не? Пока не звучит убедительно, если честно




Ты мыслишь, как скриптер, а следовало бы мыслить как разработчик SA:MP. Тот самый разработчик, которому плевать на скриптеров и на всю аудиторию в целом (за исключением денег, естественно).
Если бы он думал о логике, он бы давно уже сделал соответствие макс. длины ника в клиенте значению MAX_PLAYER_NAME. Но воз и ныне там...

Так а как тогда быть с возможностью добавлять префиксы к никам? Вот зашёл я на твой сервер и ник у меня равен 20 символам, а у тебя на сервере система банд, которая позволяет добавлять префикс из трёх символов к нику. С текущей "нелогичной" версией MAX_PLAYER_NAME такое вполне возможно и проблем с этим не будет (например, при подсчёте кол-ва ячеек для форматирования чата, дабы отображать и префикс, и сам ник). А как быть в случае с твоей версией, где MAX_PLAYER_NAME будет ровна 20?
Разве вообще Куй виноват в том, что сообщество не хочет вникать в клиент? Ведь эта фишка с 20-ю символами задокументирована (https://wiki.sa-mp.com/wiki/GetPlayerName) и те, кто хоть немного разбираются в функционале мультиплеера, прежде чем писать свои скрипты, те знают про эту особенность.
Куй виноват только в том, что он нуль-символ не учёл в этом макросе. Хотя и тут его можно понять, ибо такой макрос пригодился бы только для создания массивов, в основном.


И да, раньше уже были случаи с недокументированными изменениями. Вот пример одного из них в 0.3.7:
Ну ты сравнил смену текстурок и подобного рода изменение...





А может быть такая ошибка закралась только в код проверки домов/машин/админки? Они же не зависят друг от друга.
Эмм, у тебя макрос MAX_PLAYER_NAME уже изменён на 21 символ. Следовательно, при входе, когда ты будешь записывать ник игрока в массив, ты так же запишешь всего 20 символов, а всё остальное отбросишь. И в таблицу с аккаунтами отправишь ровно 20 символов => если обрубок твоего ника будет совпадать с ником другого игрока, то MySQL найдёт этот аккаунт и предложит тебе авторизироваться. Ты никак не проникнешь на сервер с ником в 24 символа, при этом пройдя регистрацию, заточенную под 20 символов.




С помощью SetPlayerName можно установить ник не до 20, а до 24 символов, т.е. до MAX_PLAYER_NAME.

Как я уже писал ранее, ты должен ограничивать игрока именно 20-ю символами, ибо если он введёт больше 20 символов и аккаунт сохранится с таким ником, в следующий раз он просто не сможет под этим ником зайти, ибо клиент заброкует ник с такой длинной. Следовательно, если ты это не учёл - всё сводится к твоей криворукости (надеюсь ты понимаешь, что, на протяжении всей беседы, я говорю не именно о тебе, а о гипотетическом скриптере, который допускает такие ошибки)




Тем не менее, возможное решение я привёл.

Решение проблемы, которая вообще изначально не поднималась ;) И ежу понятно, что в случае изменения макроса со стороны разработчиков мультиплеера, нужно менять значение в БД. Только вот с текущей длиной ты ошибся, ибо в БД так же, как и в клиент, не стоит писать ник длиннее 20 символов, если у тебя система аккаунтов не имеет ветвистый вид (один основной ник и от него уже имеется возможность зарегистрировать несколько других аккаунтов со своими никами по типу сингла из GTA 5). И причину я описал выше




Может, посвятишь меня, в чём именно?

Хмм, прости, вот тут немного неправильно тебя изначально понял (перепрочёл и понял, что в первом случае ты говоришь о том, что могут забыть изменить константу, а во втором - что обязательно предупредят об изменении. Сначала понял так, что ты говоришь, мол "разработчики могут забыть изменить константу, но константу они изменить не забудут", если уж совсем утрировать).



Хаки, которые "кажутся мне удобными"? Например?
Я не говорил конкретно про тебя, а имел ввиду сообщество в целом. Думаю, нет нужды приводить примеры? Но если всё же нужно - могу пошарить в архивах сего форума и процитировать




И что ты хочешь этим сказать?

То, что говорил и ранее: нужно давать людям всю информацию по поводу того или иного вопроса, а не ограничиваться только тем, что ты считаешь правильным. Сказать: "тыкать в людей ножом - это плохо", может каждый, а ты попробуй объяснить почему это плохо и тогда ты уменьшишь риски свершения подобного действия (тыканья ножом) к минимуму




Речь была о тех, кто не способен обучаться.

А как ты их отсеиваешь, если не секрет?




Уж лучше так, чем ещё один г-и

А можно было создать второй Хабр, только более узконаправленный. Но тут ситуация повторяется как с серверами в SA-MP: в далёком 2008-ом году был придуман GF (а может что-то и ещё раньше было), в котором основой Role Play режима была система уровней и прочего, и эту идею по сей день доят до последнего. А потом удивляются почему все сервера похожи друг на друга, когда любой "уникальный" мод начинается с копирования GF

Daniel_Cortez
31.03.2016, 09:55
А разве не об этом изначально была речь?...
Если ты не заметил, речь изначально шла не об изменении стандартных макросов, а о выдумывании своих в то время, как ты сам никакого отношения к SA:MP не имеешь и о предстоящих изменениях узнаешь в самый последний (и, возможно, далеко не в самый подходящий) момент.



Например?
Начиная с просто неприятных (если ты предлагаешь уменьшить значение именно в MAX_PLAYER_NAME, то будет немного сложнее уместить ник с префиксом) и заканчивая уязвимостями, пример которых я уже привёл.



Несколько ячеек в случае с GetPlayerName в OnPlayerConnect + несколько ячеек в случае с массивом для хранения приветствия при входе + ещё несколько ячеек при запросе в бд... Данный макрос используется часто и "несколько ячеек" могут превратиться в пару сотен.
В любом случае, это ничто по сравнению с экономией при уменьшении MAX_PLAYERS: если величина данных об аккаунте занимает 100-200 ячеек, то при уменьшении MAX_PLAYERS с 1000 до 50 этих ячеек можно сэкономить ~100 000-200 000 - и это ещё не считая других массивов, у которых тоже размер MAX_PLAYERS, с ними экономия достигает мегабайтов памяти.



Да и, опять же, хочется вспомнить политику двойных стандартов, когда в одном случае изобретать велосипеды - нормально, а в другом - греху подобно. КОгда это экономия лишней пары ячеек стала чем-то плохим?
Тогда, когда она начинает усложнять дальнейшую разработку мода без сильной на то необходимости, вносит новые ограничения в процесс игры (то же урезание длины ника, например) или угрожает появлением новых уязвимостей. Да, желание сэкономить немного памяти - это хорошо, но нужно знать меру.



Как и на ознакомление с остальным кодом, не? Пока не звучит убедительно, если честно
Если проект грамотно структурирован, то не обязательно ознакамливаться с каждым файлом и с каждой строчкой кода, достаточно из названий модулей узнать, какой из них за что отвечает, а с принципом их работы ознакамливаться лишь потом, при необходимости.
Твой же подход с новыми константами может повлиять не на какой-то отдельный модуль, а на всю кодовую базу проекта в целом.
Новому же разработчику, помимо тех правил, которые на него накладывают используемые в проекте библиотеки (в данном случае инклуды SA:MP), придётся держать в голове и твоё исключение из правил (возможно, даже не понимая, зачем оно было придумано).



Так а как тогда быть с возможностью добавлять префиксы к никам? Вот зашёл я на твой сервер и ник у меня равен 20 символам, а у тебя на сервере система банд, которая позволяет добавлять префикс из трёх символов к нику. С текущей "нелогичной" версией MAX_PLAYER_NAME такое вполне возможно и проблем с этим не будет (например, при подсчёте кол-ва ячеек для форматирования чата, дабы отображать и префикс, и сам ник). А как быть в случае с твоей версией, где MAX_PLAYER_NAME будет ровна 20?
В таком случае следовало бы по уму сделать две константы: MAX_PLAYER_NAME и MAX_PLAYER_NAME_PREFIX (можно ещё MAX_PLAYER_TOTAL_NAME), а по возможности отделить сам префикс от ника, сделав отдельные функции для получения и установки префикса.
И да, где-нибудь вообще сказано, что та багофича с несоответствием MAX_PLAYER_NAME в клиенте и инклудах предназначена именно для префиксов, а не просто глупый промах разработчика (как это обычно и бывает)?



Разве вообще Куй виноват в том, что сообщество не хочет вникать в клиент?
А разве сообщство виновато в том, что у куя всё делается через энное место?
Ок, виновато, но лишь в том, что позволило стать SA:MP популярным, ведь хомячкам нет дела до его уродливого внутреннего строения.



Ну ты сравнил смену текстурок и подобного рода изменение...
Опять же, мыслишь как скриптер, для куя же это изменение может показаться незначительным - он же не держит никаких серверов.
И да, я не сравнил, а лишь привёл пример того, что раньше подобные случае с недокументированными изменениями уже были. Ещё одним можно считать "скрытое" обновление 0.3.7 R2-1-1, которое было 1 августа, через месяц после выхода R2-1, правда, о больше нём вообще ничего точно не известно.



Эмм, у тебя макрос MAX_PLAYER_NAME уже изменён на 21 символ.
Разговор был не про MAX_PLAYER_NAME (значение этой константы осталось неизменным, 24), а про выдуманную тобой константу "C_MAX_PLAYER_NAME" (20). Хорошо, дальше в этой теме я буду употреблять именно её название.



Решение проблемы, которая вообще изначально не поднималась ;)
Ну почему же не поднималась, ты сам про неё упомянул.
И некоторые проблемы лучше решать не по мере поступления, а продумывать и учитывать с самого начала, иначе потом может понадобиться вносить радикальные (и отнюдь не самые изящные в техническом плане) изменения, чтобы скрыть (замечу, не исправить, а именно скрыть) недостатки в изначальной архитектуре проекта.



Я не говорил конкретно про тебя, а имел ввиду сообщество в целом. Думаю, нет нужды приводить примеры? Но если всё же нужно - могу пошарить в архивах сего форума и процитировать
В таком случае, я не пойму, кому был адресован ответ, ведь изначально он звучал, как обвинение в мою сторону.
Напомню, речь шла о двойных стандартах:

По моей логике не нужно иметь двойных стандартов и продвигать только те хаки, которые именно тебе кажутся удобными, а все остальные гнобить :3



То, что говорил и ранее: нужно давать людям всю информацию по поводу того или иного вопроса, а не ограничиваться только тем, что ты считаешь правильным. Сказать: "тыкать в людей ножом - это плохо", может каждый, а ты попробуй объяснить почему это плохо и тогда ты уменьшишь риски свершения подобного действия (тыканья ножом) к минимуму
В любом случае, подход с воспитанием в детсаде или школе мало чем связан со способностями в плане написания кода. Само по себе программирование - это работа в некой виртуальной реальности, при которой всё приходится изучать практически с чистого листа.



А как ты их отсеиваешь, если не секрет?
Мне незачем кого-либо отсеивать, я не обучаю никого индивидуально.



А можно было создать второй Хабр, только более узконаправленный.
В том-то и дело, что проект получится чересчур узконаправленный. Из самой сферы разработки в SA:MP или MTA мало что можно взять, чтобы каждый день (или, хотя бы, два) заполнять фид интересными статьями. С модерированием статей/комментариев и отсеиванием говнокода тоже могут возникнуть проблемы.
Как результат, проект просто не сможет набрать нужную аудиторию. А если сделать слишком мягкие правила, то он превратится в ещё один г-и, только видоизменённый.

DeimoS
31.03.2016, 10:57
Если ты не заметил, речь изначально шла не об изменении стандартных макросов, а о выдумывании своих в то время, как ты сам никакого отношения к SA:MP не имеешь и о предстоящих изменениях узнаешь в самый последний (и, возможно, далеко не в самый подходящий) момент.

Я говорю про то начало, где я уже предложил менять сам MAX_PLAYER_NAME :D
После моего сообщения о изменении MAX_PLAYER_NAME мы говорили лишь о изменении макроса и я что-то не вижу упоминаний о создании дополнительных...




Начиная с просто неприятных (если ты предлагаешь уменьшить значение именно в MAX_PLAYER_NAME, то будет немного сложнее уместить ник с префиксом) и заканчивая уязвимостями, пример которых я уже привёл.
Так а причём тут префикс, если я предлагаю изменить макрос только тогда, когда к нику 100% не будет добавлен никакой префикс?
Ну а про уязвимости ниже




В любом случае, это ничто по сравнению с экономией при уменьшении MAX_PLAYERS: если величина данных об аккаунте
Почему же? Не обязательно же MAX_PLAYER_NAME изменится на большое число ячеек. Я могу, например, создать 5 стандартных ботов, которые занимают слоты с последнего. По твоей логике, их в массивах учитывать уже не обязательно и пусть эти 5 ячеек висят без дела




Тогда, когда она начинает усложнять дальнейшую разработку мода без сильной на то необходимости, вносит новые ограничения в процесс игры (то же урезание длины ника, например) или угрожает появлением новых уязвимостей. Да, желание сэкономить немного памяти - это хорошо, но нужно знать меру.
Ты так и не привёл никаких аргументов в пользу того, что подобное изменение макроса как-то усложняет код или угрожает появлением уязвимостей.
Как уже было сказано ранее, если код передаётся из рук в руки, там должны быть комментарии. На код с комментариями ты потратишь не больше времени, нежели ты бы потратил на разбор кода без подобного макроса (или прочесть комментарий "MAX_PLAYER_NAME подогнана под лимиты мультиплеера" - это сверхсложная задача?).
С уязвимостями мы тоже, вроде как, всё уяснили.




Если проект грамотно структурирован, то не обязательно ознакамливаться с каждой строчкой кода, достаточно из названий модулей узнать, какой из них за что отвечает, а с принципом их работы ознакамливаться лишь потом, при необходимости.

Ты, по-моему, путаешь SA-MP и создание *удалено //DC*, коим ты занимаешься...
Да и речь шла не о понимании предназначения каких-то отдельных систем, а о понимании предназначения всего одного макроса. Ты сейчас пытаешься сравнить бумажный самолётик и Боинг :(


Твой же подход с новыми константами может повлиять на на какой-то отдельный модуль, а на всю кодовую базу проекта в целом.
Новому же разработчику, помимо тех правил, которые на него накладывают используемые в проекте библиотеки (в данном случае инклуды SA:MP), придётся держать в голове и твоё исключение из правил (возможно, даже не понимая, зачем оно было придумано).

Ну тогда говорю же, давай вообще откажемся от каких-либо макросов и написания свои функций, а будем весь код писать прямо в коллбэках. Зачем заставлять бедного нового разработчика (которого, с вероятностью в 99.9% и не будет) держать в памяти имена этих самых макросов и функций, а так же их предназначение?
Хотя ладно, ты имеешь ввиду, как я понимаю, не совсем то, о чём я говорю. Просто не будем ходить далеко и вспомним твоё "MAX_PLAYER_NAME+1", которое ты считаешь исключительно верным (даже при подключении к серверу, хотя в тот момент ник никак не сможет быть равным 24-ем символам). Можно провести опрос и посмотреть сколько людей поймёт для чего ты прибавляешь к макросу единицу, а потом сделаем тот же опрос с моим кодом. И сравнить результаты. Да и если новый разработчик не знает про этот прикол с нуль-символом, у него так же могут возникнуть проблемы, когда вдруг последний символ начнёт исчезать в новых системах. Тогда что, подстраиваться под такие случаи и отказаться от "+1"?




В таком случае следовало бы по уму сделать две константы: MAX_PLAYER_NAME и MAX_PLAYER_NAME_PREFIX (можно ещё MAX_PLAYER_TOTAL_NAME), а по возможности отделить сам префикс от ника, сделав отдельные функции для получения и установки префикса.

А разве не об этом изначально говорил? Хотя простите, я же напрямую не сказал "делайте макрос MAX_PLAYER_NAME_PREFIX равным 25 символам и MAX_PLAYER_NAME равным 21 символу", а попытался объяснить суть, дабы каждый смог осознать проблему и предпринять какие-то меры.


И да, где-нибудь вообще сказано, что та багофича с несоответствием MAX_PLAYER_NAME в клиенте и инклудах предназначена именно для префиксов, а не глупый промах разработчика (как чаще всего и бывает)?
Например тут (http://wiki.sa-mp.com/wiki/SetPlayerName)?



А разве сообщство виновато в том, что у куя всё делается через энное место?

Ну а как ты предлагаешь сделать иначе?

Ок, виновато, но лишь в том, что позволило стать SA:MP популярным, ведь хомячкам нет дела до его уродливого внутреннего строения.

Это уже проблема не конкретно сообщества SA-MP, а всего человечества в целом. Общество потребления и всё такое. Но это уже другой разговор



Опять же, мыслишь как скриптер, для куя же это изменение может показаться незначительным - он же не держит никаких серверов.
И да, я не сравнил, а лишь привёл пример того, что раньше подобные случае с недокументированными изменениями уже были. Ещё одним можно считать обновление 0.3.7 R2-1-1, которое было 1 августа, через месяц после выхода R2-1 (правда, о нём пока вообще ничего точно не известно).
Ну тогда он может и про 0.4 забыл сообщит, а оно уже готово? И все предыдущие версии выпускались так долго просто потому что он забывал их опубликовать? Это не аргументация, а уход в "если бы, да кабы". С таким же успехом он вообще может закрыть SA-MP и все труды будут насмарку. Что, отказаться теперь от разработки скриптов?



Разговор был не про MAX_PLAYER_NAME (значение этой константы осталось неизменным, 24), а про выдуманную тобой константу "C_MAX_PLAYER_NAME" (20). Хорошо, дальше в этой теме я буду употреблять именно её название.

C_MAX_PLAYER_NAME была выдумана не мной, если ты не заметил. Я лишь объяснил, что в MAX_PLAYER_NAME учитывается и место под префикс, которое во многих случаях просто не нужно, а так же показал пример того, как можно контролировать изменение MAX_PLAYER_NAME со стороны разработчиков мультиплеера. Каких-то конкретных констант я не давал.



Ну почему же не поднималась, ты сам про неё упомянул.
И некоторые проблемы лучше решать не по мере поступления, а продумывать и учитывать с самого начала, иначе потом может понадобиться вносить радикальные (и отнюдь не самые изящные в техническом плане) изменения, чтобы исправить недостатки в изначальной архитектуре проекта.
Я её поднял лишь как доказательство того, что проблем в любом случае не избежать, если Куй вдруг изменит размер ника. И я не искал решение этой проблемы, а прямо там намекнул на то, что размер столбца придётся править вручную




В таком случае, я не пойму, кому был адресован ответ, ведь изначально он звучал, как обвинение в мою сторону.
Напомню, речь шла о двойных стандартах:

Я ещё в предыдущем сообщении говорил, что под словом "ты" я имел ввиду далеко не тебя. Изначально я надеялся, что ты (теперь уже действительно ты) поймёшь, что обвинения из разряда "если ты криворукий, естественно работать не будет" не относятся к тебе, но нет :с



В любом случае, подход с воспитанием в детсаде или школе мало чем связан со способностями в плане написания кода. Само по себе программирование - это работа в некой виртуальной реальности, при которой всё приходится изучать практически с чистого листа.
Как и при строительстве или сборке лайнера. Везде имеются основы, которые закладываются в детском саду и школе. В том числе и умение скептически воспринимать информацию




Мне незачем кого-либо отсеивать, я не обучаю никого индивидуально.
При этом ты их отсеиваешь, говоря, что им не место на этом форуме. Только как ты определяешь их - непонятно




В том-то и дело, что проект получится чересчур узконаправленный. Из самой сферы разработки в SA:MP или MTA мало что можно взять, чтобы каждый день (или, хотя бы, два) заполнять фид интересными статьями. С модерированием статей/комментариев и отсеиванием говнокода тоже могут возникнуть проблемы.
Как результат, проект просто не сможет набрать нужную аудиторию. А если сделать слишком мягкие правила, то он превратится в ещё один г-и, только видоизменённый.

Он получился не то чтоб узконаправленный. Просто контент в нём, в основном, создан для более-менее разобравшихся в основах. Да и атмосфера тут не особа дружелюбна к новичкам, ибо на любые их попытки хоть что-то создать, их сразу посылают на г-и

Daniel_Cortez
31.03.2016, 20:04
Я говорю про то начало, где я уже предложил менять сам MAX_PLAYER_NAME :D
После моего сообщения о изменении MAX_PLAYER_NAME мы говорили лишь о изменении макроса и я что-то не вижу упоминаний о создании дополнительных...
Изначально это замечание адресовалось не столько тебе, сколько VVWVV. Ты же начал возражать, хоть это и было недоразумением.

Для большего удобства лучше сделать так:


#define SUB_MAX_PLAYER_NAME (4)
#define C_MAX_PLAYER_NAME (MAX_PLAYER_NAME - SUB_MAX_PLAYER_NAME)
#assert ((C_MAX_PLAYER_NAME + SUM_MAX_PLAYER_NAME) == MAX_PLAYER_NAME)[/PHP]



Так а причём тут префикс, если я предлагаю изменить макрос только тогда, когда к нику 100% не будет добавлен никакой префикс?
Если ты действительно объясняешь другим возможные негативные последствия, то вряд ли на сервере произойдёт что-то неожиданное.
Главное, чтобы те, кому ты предлагаешь менять стандартные константы, полностью осознавали, на что идут, а не слепо гнались за оптимизацией.



Почему же? Не обязательно же MAX_PLAYER_NAME изменится на большое число ячеек. Я могу, например, создать 5 стандартных ботов, которые занимают слоты с последнего. По твоей логике, их в массивах учитывать уже не обязательно и пусть эти 5 ячеек висят без дела
Если уменьшить значение в MAX_PLAYERS до 50 и в server.cfg тоже выставить 50 слотов, то боты окажутся в слотах с 49 по 45.



Ты так и не привёл никаких аргументов в пользу того, что подобное изменение макроса как-то усложняет код или угрожает появлением уязвимостей.
Если для тебя накапливание новых исключений из правил не аргумент, то я даже не знаю, есть ли смысл тебе что-либо здесь доказывать.



Ты, по-моему, путаешь SA-MP и создание *удалено //DC*, коим ты занимаешься...
Я же просил не распространяться об этом -_-



Да и речь шла не о понимании предназначения каких-то отдельных систем, а о понимании предназначения всего одного макроса. Ты сейчас пытаешься сравнить бумажный самолётик и Боинг :(
... макроса, который, как ты сам говорил, может изменить логику всего мода.



Ну тогда говорю же, давай вообще откажемся от каких-либо макросов и написания свои функций, а будем весь код писать прямо в коллбэках. Зачем заставлять бедного нового разработчика (которого, с вероятностью в 99.9% и не будет) держать в памяти имена этих самых макросов и функций, а так же их предназначение?
Вижу, ты в упор не понимаешь разницы между написанием своего кода и созданием кода, дополняющего чужой нестабильный код.



Можно провести опрос и посмотреть сколько людей поймёт для чего ты прибавляешь к макросу единицу, а потом сделаем тот же опрос с моим кодом. И сравнить результаты.
Ну узнаем мы, сколько людей не в курсе про нуль-символ, и что с того?



А разве не об этом изначально говорил? Хотя простите, я же напрямую не сказал "делайте макрос MAX_PLAYER_NAME_PREFIX равным 25 символам и MAX_PLAYER_NAME равным 21 символу", а попытался объяснить суть, дабы каждый смог осознать проблему и предпринять какие-то меры.
Добавлением констант для SA:MP должен заниматься сам разработчик мультиплеера, а не рядовые скриптеры.
Можно было бы попросить куя добавить те константы или что-то уже сделать с той багофичей, но пока он продолжает прятаться в своём бункере, это нереально.
А раз так, то остаётся лишь пользоваться тем, что есть: MAX_PLAYER_NAME.



Просто не будем ходить далеко и вспомним твоё "MAX_PLAYER_NAME+1", которое ты считаешь исключительно верным (даже при подключении к серверу, хотя в тот момент ник никак не сможет быть равным 24-ем символам).

Да и если новый разработчик не знает про этот прикол с нуль-символом, у него так же могут возникнуть проблемы, когда вдруг последний символ начнёт исчезать в новых системах. Тогда что, подстраиваться под такие случаи и отказаться от "+1"?
Как я уже сказал, пользоваться тем, что есть: MAX_PLAYER_NAME под длину ника и +1 под нуль-символ.
Те 4 неиспользованные ячейки в OnPlayerConnect мало что изменят в работе сервера, но зато удастся добиться унификации с объявлениями буферов под ник в остальном коде и избавиться от ещё одного "исключения из правил" в OPC.



Например тут (http://wiki.sa-mp.com/wiki/SetPlayerName)?
Я в курсе, но там эта багофича задокументирована в стиле "это баг, но им можно воспользоваться так-то, так-то".
Т.е. там нигде не написано, была ли эта багофича создана конкретно под префиксы, равно как и не сказано о том, была ли она вообще сделана намеренно.



Ну а как ты предлагаешь сделать иначе?
Тщательно продумывать архитектуру мультиплеера и всех нововведений перед их реализацией, а не "тяп-ляп - и в релиз". Очевидно же.



Это не аргументация, а уход в "если бы, да кабы".
...

Нет, я понимаю, что в случае с SA:MP просто глупо надеяться на какие-то крупные изменения и моя критика выглядит как раздувание слона из мухи.

Не привыкайте быдлокодить из-за SA:MP.



С таким же успехом он вообще может закрыть SA-MP и все труды будут насмарку. Что, отказаться теперь от разработки скриптов?
Из крайности в крайность...



C_MAX_PLAYER_NAME была выдумана не мной, если ты не заметил.
Да, об этом уже сказано выше.



При этом ты их отсеиваешь, говоря, что им не место на этом форуме.
Не отсеиваю, а констатирую факт существования таких людей. Если бы я их отсеивал, то говорил бы о конкретных людях.



Да и атмосфера тут не особа дружелюбна к новичкам, ибо на любые их попытки хоть что-то создать, их сразу посылают на г-и
Будь бы тут что-то типа хабра, они б просто превратились в собирателей минусов. Невелика разница.

DeimoS
01.04.2016, 13:59
Если ты действительно объясняешь другим возможные негативные последствия, то вряд ли на сервере произойдёт что-то неожиданное.
Главное, чтобы те, кому ты предлагаешь менять стандартные константы, полностью осознавали, на что идут, а не слепо гнались за оптимизацией.

Я изначально рассказал всем логику составления этого макроса. И про "неожиданное" я тебе уже говорил.

А на остальное уже не буду отвечать, ибо пора прекращать эту полемику, которая начинает перерастать в недопонимания и стрелометание. Как я уже сказал выше, я свою точку зрения по поводу этого вопроса озвучил. Ты озвучил свою. У каждого своя голова на плечах, так что пусть каждый сам и решает - готов ли он взять на себя ТАКУЮ "ответственность" и помнить СТОЛЬКО новой информации.
А за то, о чём ты просил не распространяться, прости :( Запамятовал

Redsan
21.06.2016, 02:32
Я правильно считаю?


new query_string[85-12+MAX_PLAYER_NAME+32+64];
format(query_string, sizeof(query_string), "INSERT INTO `accounts` (`player_name`, `password`, `email`) VALUES ('%s', '%s', '%s')", pInfo[playerid][pName], password, email);
// максимальная длина password - 32
// максимальная длина email - 64

Или объясните на этом примере как высчитывались значения?

stock SaveAccount(playerid)
{
new query_string[(21)+(16+11)+(20+MAX_PLAYER_NAME)+(16+32)] = "UPDATE `accounts` SET";

format(query_string, sizeof(query_string), "%s `player_name` = '%s',", query_string, pInfo[playerid][pName]);
format(query_string, sizeof(query_string), "%s `password` = '%s'", query_string, pInfo[playerid][pPassword]);

format(query_string, sizeof(query_string), "%s WHERE `id` = '%d'", query_string, pInfo[playerid][pID]);
mysql_function_query(mysql_connect_id, query_string, false, "", "");
return 1;
}

m1n1vv
22.06.2016, 14:32
UPDATE `accounts` SET //(21)
%s `player_name` = '%s', //(20+MAX_PLAYER_NAME)
%s `password` = '%s' //(16+32)
%s WHERE `id` = '%d' //(16+11)

Например (16+11). Первое число это "длина" текста в кавычках, а второе - что выведут %s и %d.

Тот код можно оформить и так:


stock SaveAccount(playerid)
{
static const str[] = "UPDATE `accounts` SET `player_name` = '%s', `password` = '%s' WHERE `id` = '%d'";
new string[sizeof str+MAX_PLAYERS_NAME+32+11-2*3];
format(string, sizeof string, str,
pInfo[playerid][pName],
pInfo[playerid][pPassword],
pInfo[playerid][pID]
);
mysql_function_query(mysql_connect_id, string, false, "", "");
return 1;
}

Daniel_Cortez
22.06.2016, 19:52
Я правильно считаю?


new query_string[85-12+MAX_PLAYER_NAME+32+64];
format(query_string, sizeof(query_string), "INSERT INTO `accounts` (`player_name`, `password`, `email`) VALUES ('%s', '%s', '%s')", pInfo[playerid][pName], password, email);
// максимальная длина password - 32
// максимальная длина email - 64



const MAX_PLAYER_PASSWORD = 32;
const MAX_PLAYER_EMAIL = 64;
enum pInfo
{
pName[MAX_PLAYER_NAME + 1],
pPassword[MAX_PLAYER_PASSWORD + 1],
pEmail[MAX_PLAYER_EMAIL + 1],
// ...
};



new fmt_str[] = "INSERT INTO `accounts` (`player_name`, `password`, `email`) VALUES ('%s', '%s', '%s')";
new query[sizeof(fmt_str) + (-2+MAX_PLAYER_NAME) + (-2+MAX_PLAYER_PASSWORD) + (-2+MAX_PLAYER_EMAIL)];
format(query, sizeof(query), fmt_str, pInfo[playerid][pName], pInfo[playerid][pPassword], pInfo[playerid][pEmail]);
// А вообще здесь следовало бы использовать mysql_format. Только не спрашивайте, почему.

m1n1vv
22.06.2016, 23:24
const MAX_PLAYER_PASSWORD = 32;
const MAX_PLAYER_EMAIL = 64;



enum MAX_LENGHT
{
MAX_PLAYER_PASSWORD = 32,
MAX_PLAYER_EMAIL = 64
}
Удобней в чтении кода

Daniel_Cortez
23.06.2016, 14:28
enum MAX_LENGHT
{
MAX_PLAYER_PASSWORD = 32,
MAX_PLAYER_EMAIL = 64
}
Удобней в чтении кода
Удобнее в плане большего расхода пространства на экране или засорения глобального пространства имён лишним идентификатором MAX_LENGHT (не говоря уже об опечатке в названии)?
Вообще "enum" - это сокращение от "enumeration", что переводится как "перечисление". Оператор enum предназначен для перечисления констант, значения которых зависят друг от друга (я бы написал "следуют" друг за другом, но в Pawn для элементов перечисления можно сделать не только инкремент, но и декремент или даже битовый сдвиг).
В вашем же примере значения MAX_PLAYER_PASSWORD и MAX_PLAYER_EMAIL никак не зависят друг от друга, поэтому непонятно, в чём вообще смысл об их объявления в enum.
Да, это допустимый стиль с точки зрения корректности синтаксиса, но, ИМХО, чтобы считать его "удобным", нужно обладать довольно извращённым чувством удобства.
С таким же успехом можно объявлять константы так:


enum {MAX_PLAYER_PASSWORD = 32};
enum {MAX_PLAYER_EMAIL = 64};

Но почему-то так никто не делает. По очевидным причинам.

Nexius_Tailer
24.06.2016, 11:59
Да, это допустимый стиль с точки зрения корректности синтаксиса, но, ИМХО, чтобы считать его "удобным", нужно обладать довольно извращённым чувством удобства.
С таким же успехом можно объявлять константы так:


enum {MAX_PLAYER_PASSWORD = 32};
enum {MAX_PLAYER_EMAIL = 64};

Но почему-то так никто не делает. По очевидным причинам.
Почему это извращённым чувством удобства? К примеру имеем мы кучу дефайнов, большинство которых начинаются с "MAX_". Максимальным может быть не только размер, но и количество чего-либо. Поэтому довольно удобное и наглядное разграничивание.
Да и вообще, если уж говорить о том, чем кто пользуется, то это не const, а:

#define

Тем не менее другие варианты тоже существуют и имеют место быть. Кому как удобнее?

Daniel_Cortez
24.06.2016, 14:54
Почему это извращённым чувством удобства? К примеру имеем мы кучу дефайнов, большинство которых начинаются с "MAX_". Максимальным может быть не только размер, но и количество чего-либо.
Потому что прочитайте полностью предыдущий пост.
MAX_PLAYER_PASSWORD и MAX_PLAYER_EMAIL как-то зависят друг от друга? Нет. Обе константы обозначают максимальные длины строк - и на этом всё. Можно спокойно изменить MAX_PLAYER_PASSWORD - на значении MAX_PLAYER_EMAIL это никак не отразится.



Поэтому довольно удобное и наглядное разграничивание.


const MAX_HOUSES = 300;

const MAX_PLAYER_PASSWORD = 32;
const MAX_PLAYER_EMAIL = 64;

new const Float:fishing_spots[][3] =
{
// ...
};

Пустые строки. Довольно древний лайфхак - и тоже весьма наглядное разграничивание.
Если же взять тот пример с enum - всё равно ж придётся ставить пустые строки до и после перечисления.

Попробую предугадать ответ:

А я не буду ставить пустые строки - с enum разграничение и так уже есть.
Хорошо, допустим:


const MAX_HOUSES = 300;
enum
{
MAX_PLAYER_PASSWORD = 32,
MAX_PLAYER_EMAIL = 64
};
new const Float:fishing_spots[][3] =

Будь там полностью пустые строки, разделение было бы очевидным, но в таком виде границы перечисления становятся более "размытыми".



Да и вообще, если уж говорить о том, чем кто пользуется, то это не const, а:

#define
Так я ничего и не говорил против #define, речь была конкретно о бессмысленности enum для не зависящих друг от друга констант.
На самом деле в модах куда чаще объявляют константы с помощью #define (вернее, это уже не константы, а макросы), но единственное их преимущество перед объявлением через const - возможность использования с оператором стрингизации:


#define MAX_AD_MESSAGE 80
// ...
CMD:ad(playerid, params[])
{
// ...
if (strlen(params) > 80)
return SendClientMessage(playerid, -1, "ОШИБКА: Текст сообщения должен быть не длиннее " #MAX_AD_MESSAGE " символов.");
// ...
}

Если объявить MAX_AD_MESSAGE с помощью const, такой трюк не прокатит.



Тем не менее другие варианты тоже существуют и имеют место быть. Кому как удобнее?
Целью моего поста было лишь донести нецелесообразность использования конкретных вариантов, а не навязать использование только одного.
Стиль кодинга следует с самого начала хорошо продумывать - иначе вместо кода можно получить кучу едва работающих, прибитых друг к другу гвоздями костылей и заплаток, которую невозможно структурировать, не переписав всё с нуля. И пока найдёшь в этой куче то, что нужно (допустим, константу, название которой забыл), вспомнишь столько непристойных слов, что на целый словарь хватит.

Nexius_Tailer
24.06.2016, 15:31
Хорошо, допустим:


const MAX_HOUSES = 300;
enum
{
MAX_PLAYER_PASSWORD = 32,
MAX_PLAYER_EMAIL = 64
};
new const Float:fishing_spots[][3] =

Будь там полностью пустые строки, разделение было бы очевидным, но в таком виде границы перечисления становятся более "размытыми".
Да нет, всё отлично


enum MAX_COUNT
{
MAX_HOUSES = 300,
MAX_BUSINESS = 250,
MAX_FLATS = 100
}

enum MAX_LENGHT
{
MAX_PLAYER_PASSWORD = 32,
MAX_PLAYER_EMAIL = 64
}

Desulaid
24.06.2016, 16:45
Да нет, всё отлично


enum MAX_COUNT
{
MAX_HOUSES = 300,
MAX_BUSINESS = 250,
MAX_FLATS = 100
}

enum MAX_LENGHT
{
MAX_PLAYER_PASSWORD = 32,
MAX_PLAYER_EMAIL = 64
}

Я тоже люблю мороженое с рыбой в одном рожке, ведь это все еда.

Не вижу смысла в использовании оператора enum для такого извращения, да и код выглядит как-то не очень красиво. И вообще КТО ТАК ДЕЛАЕТ?!

Nexius_Tailer
24.06.2016, 16:53
Я тоже люблю мороженое с рыбой в одном рожке, ведь это все еда.

Не вижу смысла в использовании оператора enum для такого извращения, да и код выглядит как-то не очень красиво. И вообще КТО ТАК ДЕЛАЕТ?!
Кому так делать хочется. Может это как-то и необычно, но в целом как вариант довольно интересный.
Да и тем более критерий "так не делает большинство" никак не портит удобность или юзабельность чего-либо.

Desulaid
24.06.2016, 18:18
Кому так делать хочется. Может это как-то и необычно, но в целом как вариант довольно интересный.
Да и тем более критерий "так не делает большинство" никак не портит удобность или юзабельность чего-либо.

Но засовывать детородные предметы себе в зад тоже можно и не факт, что так не делает кто-нибудь.

Nexius_Tailer
24.06.2016, 18:37
Но засовывать детородные предметы себе в зад тоже можно и не факт, что так не делает кто-нибудь.
Не знаю о чём ты, но я говорил о enum и конкретной реализации, а не о детородных предметах.
Если это сравнение, то нелепое

Desulaid
25.06.2016, 02:23
Не знаю о чём ты, но я говорил о enum и конкретной реализации, а не о детородных предметах.
Если это сравнение, то нелепое

Может это как-то и необычно, но в целом как вариант довольно интересный. Да и тем более критерий "так не делает большинство" никак не портит удобность или юзабельность чего-либо.

:lol:

$continue$
25.06.2016, 04:11
- Алло, 2016 как слышно?
- Мы тут для констант используем перечисляемый тип.

Советую посмотреть реализацию enum'ов в C/C++/C#/Java, зачем оно и как юзаться.

И таким образом ты конструируешь костыль и велосипед. Ты мне даешь гарантии, что скриптер писавший код в 03:00 по ошибке не забудет в enum инициализировать константу? (А перечисление идет с нуля)

Пример кода, при котором скриптер просто сфлится:



enum
{
MAX_PLAYER_PASSWORD = 32,
MAX_PLAYER_EMAIL = 64,
MAX_PLAYER_CARS,
MAX_PLAYER_HOUSE = 512
};
main()
{
printf("MAX_PLAYER_PASSWORD = %d", MAX_PLAYER_PASSWORD);
printf("MAX_PLAYER_EMAIL = %d", MAX_PLAYER_EMAIL);
printf("MAX_PLAYER_CARS = %d", MAX_PLAYER_CARS);
printf("MAX_PLAYER_HOUSE = %d", MAX_PLAYER_HOUSE);
}

Да, да я опять прыгнуть выше головы. А, то сейчас налетят голодные волки.

Хороший пример кода с enum - месяца года. Устанавливаешь январю = 1, а дальше автоматизированно будет (только, прописать название констант)

Nexius_Tailer
25.06.2016, 13:08
И таким образом ты конструируешь костыль и велосипед. Ты мне даешь гарантии, что скриптер писавший код в 03:00 по ошибке не забудет в enum инициализировать константу? (А перечисление идет с нуля)
Тогда пусть не пишет код в три часа ночи и присваивает всем элементам значения. Лично мне этот вариант понравился.
С дефайном или константой также можно забыть присвоить значение, и виноват будет в этом не способ, а ты. Не аргумент это.

Daniel_Cortez
25.06.2016, 14:52
С дефайном или константой также можно забыть присвоить значение
По поводу дефайна согласен, но с константой, если объявлять её с помощью const - компилятор "напомнит".
Кстати, если посмотреть на стандартные инклуды Pawn (core.inc, string.inc, float.inc), там ни одной константы не объявлено через #define, только через const (и ещё некоторые через enum, где это уместно).



и виноват будет в этом не способ, а ты
... в том, что выбрал способ, с которым легко ошибиться.



Тогда пусть не пишет код в три часа ночи и присваивает всем элементам значения.
Нет, ну это уже просто смешно. Может вы ещё предложите не делать в коде ни единой ошибки? Чтобы прямо вообще ни одной и всё компилировалось с первой попытки?



Лично мне этот вариант понравился.
А оно и было очевидно с самого начала, что "красота" и "необычность" метода для вас важнее, чем надёжность. Ваша отговорка из предыдущей цитаты только подтверждает это.
Именно поэтому я даже и не рассчитываю вас переубедить - но всё же надеюсь, что у других, кто смотрит эту тему, хватит чувства здравого смысла, чтобы не повторять ваших ошибок.

Nexius_Tailer
25.06.2016, 16:44
А оно и было очевидно с самого начала, что "красота" и "необычность" метода для вас важнее, чем надёжность. Ваша отговорка из предыдущей цитаты только подтверждает это.
Именно поэтому я даже и не рассчитываю вас переубедить - но всё же надеюсь, что у других, кто смотрит эту тему, хватит чувства здравого смысла, чтобы не повторять ваших ошибок.
Хах. Были бы ошибки, ибо я лично не использовал этот способ до сего.
Красота и необычность не противоречит здесь надёжности, так что про важность первого тоже неверно.
Если кому-то просто непривычно - господи, пусть использует то, что ему нравится, а то, что не нравится - просто не использует.
Я лично не увидел ни одного реального недостатка этого, кроме разве что использования enum'а немного не по назначению. Но существенного от этого ничего не произойдёт, а если так кому-то ещё и удобно - то причины не использовать это нет вообще.

П.с. Каким образом написали в core, string и float роли не играет. Опять-же это дело того, кто писал.

Edward Morra
13.10.2016, 20:42
После подсчетов по этому методу , стала некорректно работать команда, да и не только команда. Код, где используется static const

CMD:engine(playerid,params[])
{
if(!IsPlayerLogged{playerid}) return SendMe(playerid,COLOR_GREY,!" * [A] - Сначала нужно авторизоваться!");
if(GetPlayerState(playerid) == 2 && IsPlayerInAnyVehicle(playerid))
{
if(IsVehicleBike(GetPlayerVehicleID(playerid))) return false;
if(!Engine[GetPlayerVehicleID(playerid)])
{
if(Fuel[GetPlayerVehicleID(playerid)] > 0.0)
{
if(!EngineTime[playerid])
{
new Float:vHealth;
GetVehicleHealth(GetPlayerVehicleID(playerid),vHealth);
if(OrgCarInfo[GetPlayerVehicleID(playerid)][orgcFrac] == 15 && (PVar::GetInt(playerid,"Driving") == 4 || PVar::GetInt(playerid,"Driving") == 6))
{
if(!SeatBelt{playerid} && !IsVehicleA(GetPlayerVehicleID(playerid)))
{
SendMe(playerid,COLOR_GREY,!" * Перед началом движения вы обязаны пристегнуть ремень безопасности. Вы провалили экзамен!");
PVar::SetInt(playerid,"Driving",0);
acc_RemovePlayerFromVehicle(playerid);
DisablePlayerRaceCheckpoint(playerid);
SetEngineOnOff(GetPlayerVehicleID(playerid),false);
AccountInfo[playerid][LoadCharacters{playerid}][acTestAS] = 0;
licCP{playerid} = 0;
licerror{playerid} = 0;
lictesttime{playerid} = 0;
return false;
}
}
printf("заводим");
EngineTime[playerid] = 6;
FreezePlayer(playerid);
GameTextForPlayer(playerid, "~w~€AЊYCKAEM ѓ‹…‚A¦E‡’...", 5000, 4);
static const frm_str[]=" * %s пытается запустить двигатель.";
noinit:string[sizeof(frm_str)+(-2+MAX_PLAYER_NAME)];
format(string,sizeof(string),frm_str,PlayerName(playerid));
return ProxDetector(playerid,5,string,COLOR_PURPLE);
}
else return SendMe(playerid,COLOR_GREY,!" * Нельзя так часто заводить двигатель!");
}
else return SendMe(playerid,COLOR_GREY,!" * Бензобак пуст. Вызовите механиков!");
}
else
{
printf("незаводим");
static const frm_engine[]=" * %s заглушил двигатель.";
noinit:string[sizeof(frm_engine)+(-2+MAX_PLAYER_NAME)];
format(string,sizeof(string),frm_engine,PlayerName(playerid));
ProxDetector(playerid,5,string,COLOR_PURPLE);
SetEngineOnOff(GetPlayerVehicleID(playerid),false);
EngineTime[playerid] = 0;
}
}
return true;
}

vovandolg
13.10.2016, 23:06
После подсчетов по этому методу , стала некорректно работать команда, да и не только команда. Код, где используется static const
Попробуй подсчёт в массиве выполнить до пропуска инициализации

Edward Morra
14.10.2016, 12:17
Попробуй подсчёт в массиве выполнить до пропуска инициализации

например?

vovandolg
14.10.2016, 15:09
например?



new sizestr = sizeof(frm_engine)+(-2+MAX_PLAYER_NAME);
noinit:string[sizestr];

Desulaid
14.10.2016, 15:39
Попробуй подсчёт в массиве выполнить до пропуска инициализации

Это не поможет проблеме. Вы ведь никакое значение массиву не устанавливаете во время инициализации.


main()
{
static const
fmt_str[] = "%s - это была строка...";

goto noinit;
new
str[sizeof fmt_str + (-2 + 9)];
noinit:

format(str, sizeof str, fmt_str, "кака-бяка");
print(str);
}

Как тут можно вообще ждать помощи, если формулировка проблемы не ясна совсем. Что значит "после подсчетов по этому методу, стала некорректно работать команда". Что значит "некорректно"? Чего вы ожидали и что получили в итоге укажите. :dash2:

Edward Morra
14.10.2016, 17:34
Это не поможет проблеме. Вы ведь никакое значение массиву не устанавливаете во время инициализации.


main()
{
static const
fmt_str[] = "%s - это была строка...";

goto noinit;
new
str[sizeof fmt_str + (-2 + 9)];
noinit:

format(str, sizeof str, fmt_str, "кака-бяка");
print(str);
}

Как тут можно вообще ждать помощи, если формулировка проблемы не ясна совсем. Что значит "после подсчетов по этому методу, стала некорректно работать команда". Что значит "некорректно"? Чего вы ожидали и что получили в итоге укажите. :dash2:

В итоге, что я перейду на более удобный для меня, метод подсчета. Но при переходе на него - команда как бы производит заводку двигателя, но в тоже время выводит текст о том, что заглушил... Все ниже подсчета и вывода игнорируется

VVWVV
14.10.2016, 17:54
В итоге, что я перейду на более удобный для меня, метод подсчета. Но при переходе на него - команда как бы производит заводку двигателя, но в тоже время выводит текст о том, что заглушил... Все ниже подсчета и вывода игнорируется

Это баг (http://pro-pawn.ru/showthread.php?14157).

Для решения проблемы необходимо переименовать метку.

Однако существует другой способ:


#define @new%0\32%1[%2]%3; goto _noinit_%1; new %1[%2]%3; _noinit_%1:
и используй так:

@new str[10], strr[20], strrr[30];
Синтаксис лучше придумать не смог.

Однако такой синтаксис работать не будет, ибо у вас названия идентичны, а это значит, что вам необходимо переименовать какой-то из массивов.

Edward Morra
14.10.2016, 18:02
Это баг (http://pro-pawn.ru/showthread.php?14157).

Вот именно про этот баг я твердил.
Почему не наткнулся я на эту тему...
Дак, каким оптимальным вариантом решения проблемы будет являться?

ziggi
14.10.2016, 18:48
Вот именно про этот баг я твердил.
Почему не наткнулся я на эту тему...
Дак, каким оптимальным вариантом решения проблемы будет являться?

Самым лучшим решением будет забить на пропуск инициализации и писать код нормально. Ибо ты совершенно ничего не понимаешь в оптимизации (куча вызовов GetPlayerVehicleID, оптимизируешь инициализацию массива :good2:), а такие "оптимизации" только вредят. Ну или просто используй разные названия переменных.

P.S. Нахватаются от всяких, а потом не понимают где проблемы... Любые микрооптимизации можно производить только при знании того, как оно работает и для чего это делается и только после общей оптимизации кода и алгоритмов (а это оптимизировать куда сложнее).

Edward Morra
14.10.2016, 18:55
Самым лучшим решением будет забить на пропуск инициализации и писать код нормально. Ибо ты совершенно ничего не понимаешь в оптимизации (куча вызовов GetPlayerVehicleID, оптимизируешь инициализацию массива :good2:), а такие "оптимизации" только вредят. Ну или просто используй разные названия переменных.

P.S. Нахватаются от всяких, а потом не понимают где проблемы... Любые микрооптимизации можно производить только при знании того, как оно работает и для чего это делается и только после общей оптимизации кода и алгоритмов (а это оптимизировать куда сложнее).

Мог бы конкретней указать на мою некомпитентность в данном коде?
Все и рвуться, потому-что хотят что-то новое узнать, дабы не быть быдлокодером...

vovandolg
14.10.2016, 19:31
оптимизируешь инициализацию массива

А где можно почитать о правильном приёме пропуска инициализации массива или не массива, что да как вообще и для чего оно?

ziggi
14.10.2016, 20:47
А где можно почитать о правильном приёме пропуска инициализации массива или не массива, что да как вообще и для чего оно?

Не знаю, лично я этим не пользуюсь и никому не советую. Повторюсь: выигрыш будет минимальным, по сравнению с грамотной оптимизацией алгоритмов.


Мог бы конкретней указать на мою некомпитентность в данном коде?

Как минимум, все вызовы GetPlayerVehicleID, GetPlayerState, IsPlayerInAnyVehicle можно заменить одним GetPlayerVehicleID. Также вызов PVar::GetInt можно сделать единожды.
Код не оформлял (только лапшу убрал), ибо лень:

CMD:engine(playerid,params[])
{
if(!IsPlayerLogged{playerid}) return SendMe(playerid,COLOR_GREY,!" * [A] - Сначала нужно авторизоваться!");

new vehicleid = GetPlayerVehicleID(playerid);
if(vehicleid == 0) {
return 1;
}

if(IsVehicleBike(vehicleid)) return false;

if(Engine[vehicleid]) {
printf("незаводим");
static const frm_engine[]=" * %s заглушил двигатель.";
new string[sizeof(frm_engine)+(-2+MAX_PLAYER_NAME)];
format(string,sizeof(string),frm_engine,PlayerName(playerid));
ProxDetector(playerid,5,string,COLOR_PURPLE);
SetEngineOnOff(vehicleid,false);
EngineTime[playerid] = 0;
return 1;
}

if(Fuel[vehicleid] <= 0.0) {
return SendMe(playerid,COLOR_GREY,!" * Бензобак пуст. Вызовите механиков!");
}

if(EngineTime[playerid]) {
return SendMe(playerid,COLOR_GREY,!" * Нельзя так часто заводить двигатель!");
}
new Float:vHealth;
GetVehicleHealth(vehicleid,vHealth);
new driving = PVar::GetInt(playerid,"Driving");
if(OrgCarInfo[vehicleid][orgcFrac] == 15 && (driving == 4 || driving == 6))
{
if(!SeatBelt{playerid} && !IsVehicleA(vehicleid))
{
SendMe(playerid,COLOR_GREY,!" * Перед началом движения вы обязаны пристегнуть ремень безопасности. Вы провалили экзамен!");
PVar::SetInt(playerid,"Driving",0);
acc_RemovePlayerFromVehicle(playerid);
DisablePlayerRaceCheckpoint(playerid);
SetEngineOnOff(vehicleid,false);
AccountInfo[playerid][LoadCharacters{playerid}][acTestAS] = 0;
licCP{playerid} = 0;
licerror{playerid} = 0;
lictesttime{playerid} = 0;
return false;
}
}
printf("заводим");
EngineTime[playerid] = 6;
FreezePlayer(playerid);
GameTextForPlayer(playerid, "~w~€AЊYCKAEM ѓ‹…‚A¦E‡’...", 5000, 4);
static const frm_str[]=" * %s пытается запустить двигатель.";
new string[sizeof(frm_str)+(-2+MAX_PLAYER_NAME)];
format(string,sizeof(string),frm_str,PlayerName(playerid));
return ProxDetector(playerid,5,string,COLOR_PURPLE);
}

И такой ужас лишь в одной команде, страшно представить что во всём остальном скрипте творится. Уверен, что IsVehicleBike, IsVehicleA реализованы массой проверок, в ProxDetector вычисляется расстояние для всех игроков.

P.S. Уродствами, вида SendMe и PVar::SetInt ты только путаешь людей, которые будут разбираться в твоём коде.

Edward Morra
14.10.2016, 20:51
Не знаю, лично я этим не пользуюсь и никому не советую. Повторюсь: выигрыш будет минимальным, по сравнению с грамотной оптимизацией алгоритмов.



Как минимум, все вызовы GetPlayerVehicleID, GetPlayerState, IsPlayerInAnyVehicle можно заменить одним GetPlayerVehicleID. Также вызов PVar::GetInt можно сделать единожды.
Код не оформлял (только лапшу убрал), ибо лень:

CMD:engine(playerid,params[])
{
if(!IsPlayerLogged{playerid}) return SendMe(playerid,COLOR_GREY,!" * [A] - Сначала нужно авторизоваться!");

new vehicleid = GetPlayerVehicleID(playerid);
if(vehicleid == 0) {
return 1;
}

if(IsVehicleBike(vehicleid)) return false;

if(Engine[vehicleid]) {
printf("незаводим");
static const frm_engine[]=" * %s заглушил двигатель.";
new string[sizeof(frm_engine)+(-2+MAX_PLAYER_NAME)];
format(string,sizeof(string),frm_engine,PlayerName(playerid));
ProxDetector(playerid,5,string,COLOR_PURPLE);
SetEngineOnOff(vehicleid,false);
EngineTime[playerid] = 0;
return 1;
}

if(Fuel[vehicleid] <= 0.0) {
return SendMe(playerid,COLOR_GREY,!" * Бензобак пуст. Вызовите механиков!");
}

if(EngineTime[playerid]) {
return SendMe(playerid,COLOR_GREY,!" * Нельзя так часто заводить двигатель!");
}
new Float:vHealth;
GetVehicleHealth(vehicleid,vHealth);
new driving = PVar::GetInt(playerid,"Driving");
if(OrgCarInfo[vehicleid][orgcFrac] == 15 && (driving == 4 || driving == 6))
{
if(!SeatBelt{playerid} && !IsVehicleA(vehicleid))
{
SendMe(playerid,COLOR_GREY,!" * Перед началом движения вы обязаны пристегнуть ремень безопасности. Вы провалили экзамен!");
PVar::SetInt(playerid,"Driving",0);
acc_RemovePlayerFromVehicle(playerid);
DisablePlayerRaceCheckpoint(playerid);
SetEngineOnOff(vehicleid,false);
AccountInfo[playerid][LoadCharacters{playerid}][acTestAS] = 0;
licCP{playerid} = 0;
licerror{playerid} = 0;
lictesttime{playerid} = 0;
return false;
}
}
printf("заводим");
EngineTime[playerid] = 6;
FreezePlayer(playerid);
GameTextForPlayer(playerid, "~w~€AЊYCKAEM ѓ‹…‚A¦E‡’...", 5000, 4);
static const frm_str[]=" * %s пытается запустить двигатель.";
new string[sizeof(frm_str)+(-2+MAX_PLAYER_NAME)];
format(string,sizeof(string),frm_str,PlayerName(playerid));
return ProxDetector(playerid,5,string,COLOR_PURPLE);
}

И такой ужас лишь в одной команде, страшно представить что во всём остальном скрипте творится. Уверен, что IsVehicleBike, IsVehicleA реализованы массой проверок, в ProxDetector вычисляется расстояние для всех игроков.

P.S. Уродствами, вида SendMe и PVar::SetInt ты только путаешь людей, которые будут разбираться в твоём коде.

Как всегда, благодарю...

Refraktor
28.01.2017, 14:35
А как быть с двумерными массивами?

static const HeaderDialog[][] =
{
{""},
{"{%06x}Регистрация: {%06x}%s"},
{"{%06x}Авторизация: {%06x}%s"},
{"{%06x}Выбор скина"},
{"{%06x}Админ-авторизация"},
{"{%06x}Администрация online"}
};

new string[sizeof (HeaderDialog[1][])];
format (string, sizeof (string), HeaderDialog[1], COLOR_SILVER >>> 8, COLOR_RED >>> 8, pInfo[playerid][pName]);
Компилятор выдаёт ошибки:

error 001: expected token: "]", but found "-identifier-"
warning 215: expression has no effect
error 001: expected token: ";", but found "]"
error 029: invalid expression, assumed zero
fatal error 107: too many error messages on one line

VVWVV
28.01.2017, 15:17
А как быть с двумерными массивами?

static const HeaderDialog[][] =
{
{""},
{"{%06x}Регистрация: {%06x}%s"},
{"{%06x}Авторизация: {%06x}%s"},
{"{%06x}Выбор скина"},
{"{%06x}Админ-авторизация"},
{"{%06x}Администрация online"}
};

new string[sizeof (HeaderDialog[1][])];
format (string, sizeof (string), HeaderDialog[1], COLOR_SILVER >>> 8, COLOR_RED >>> 8, pInfo[playerid][pName]);
Компилятор выдаёт ошибки:

Вы не можете указать размер одного элемента массива. Более того, вы неправильно указали размер для массива string, ибо он будет инициализировать лишь одну ячейку. Вам также необходимо указать размер всех под-массивов, т.к. компилятор не умеет определять их.


static const HeaderDialog[][/* здесь должен быть размер под-массивов */] =
{
{""},
{"{%06x}Регистрация: {%06x}%s"},
{"{%06x}Авторизация: {%06x}%s"},
{"{%06x}Выбор скина"},
{"{%06x}Админ-авторизация"},
{"{%06x}Администрация online"}
};

new string[sizeof (HeaderDialog[])];
format (string, sizeof (string), HeaderDialog[1], COLOR_SILVER >>> 8, COLOR_RED >>> 8, pInfo[playerid][pName]);

vladivanovx
31.01.2017, 12:38
Сколько места занимают символы на подобии \n, \t...?

Nexius_Tailer
31.01.2017, 13:51
Сколько места занимают символы на подобии \n, \t...?
1 символ, strlen в помощь

Daniel_Cortez
10.03.2017, 07:30
В SA:MP вряд ли будет возможно сделать более 65535 игроков: это что-то вроде лимита, который можно обнаружить в некоторых местах с помощью дизассемблирования кода сервера, а учитывая, что в SA:MP добавляют всего пару мелких фич и несколько новых моделек раз в год... вряд ли лимит игроков изменится.
Этот лимит проявляется в виде бага в функциях SendDeathMessage и SendDeathMessageToPlayer: Kalcor вместо MAX_PLAYERS сделал сравнение ID игрока с INVALID_PLAYER_ID (65535), из-за чего эти две функции считают правильными не только ID от 0 до 999, но и от 1000 до INVALID_PLAYER_ID - 1 (65534) (иногда такой баг может оказаться полезным (http://pro-pawn.ru/showthread.php?12295)).
65535 - 5 символов. Следовательно, нужно из sizeof(fmt_str) отнять 2 символа (длина спецификатора "%d") и прибавить 5.

Уже не совсем помню, какими принципами я руководствовался при данном обосновании, но факт в том, что оно неправильное. ID от 1000 до 65534 являются невалидными и в обычных ситуациях не должны попадать в форматируемый текст.

Исправил в статье приведённый выше текст на новый:


На данный момент в SA-MP установлен лимит в 1000 игроков. Максимальный ID - 999 - в текстовом виде занимает 3 символа, однако в будущих версиях это число может перевалить за 1000 из-за увеличения лимита (кто знает?), поэтому я бы советовал не упираться вплотную в текущее ограничение и на всякий случай отводить под ID игрока 4 позиции в строке.
Итак, для подсчёта длины строки, в которой форматируется ID игрока, нужно из sizeof(fmt_str) отнять 2 позиции (длина спецификатора "%d") и прибавить 4.

Также в дальнейших расчётах заменил 5 на 4.

Refraktor
21.03.2017, 10:12
Почему такое в mysql_format не работает? Вылетает "error 035: argument type mismatch (argument 2)".

Daniel_Cortez
21.03.2017, 10:51
Да, действительно. Там это и не должно работать по очень простой причине:

native mysql_format(connectionHandle, output[], len, format[], {Float,_}:...);
Аргумент format в заголовке объявлен без атрибута const, из-за чего функция может принимать только неконстантные массивы, т.е. такие, у которых нет const в объявлении.
Пример:


new output[1];

static const fmt_str_0[] = ""; // массив с атрибутом const
mysql_format(conn_handle, output, sizeof(output), fmt_str_0); // error 035

static fmt_str_1[] = ""; // массив БЕЗ атрибута const
mysql_format(conn_handle, output, sizeof(output), fmt_str_0); // ok


Такая же проблема есть в функции SetPVarString и никто её не исправит по всем известной причине. Но вы можете сообщить (https://github.com/pBlueG/SA-MP-MySQL/issues) о проблеме в mysql_format разработчику плагина MySQL (заодно атрибут const следует добавить и в параметрах ещё нескольких функций плагина) - работы там не так уж и много.

VVWVV
21.03.2017, 11:00
Да, действительно. Там это и не должно работать по очень простой причине:
Такая же проблема есть в функции SetPVarString и никто её не исправит по всем известной причине. Но вы можете сообщить о проблеме в mysql_format разработчику плагина MySQL (заодно атрибут const следует добавить и в параметрах ещё нескольких функций плагина) - работы там не так уж и много.

В новой версии атрибут const добавили.



native mysql_format(MySQL:handle, output[], max_len, const format[], {Float,_}:...);

Daniel_Cortez
09.05.2017, 01:36
Обновил 1-й пост: добавил список из преимуществ и недостатков подсчёта, а также пронумеровал примеры.
Если считаете какие-то из критериев в списке необъективными - конструктивная критика всегда приветствуется.

DeimoS
09.05.2017, 02:21
Прозрачность.
Исключаются ситуации, в которых непонятно, каким образом рассчитывается размер форматного массива. Формула подсчёта всегда находится прямо в коде, и никуда не исчезает, в отличие от результатов, выдаваемых калькулятором.
Поняв принципы, по которым составляется формула, можно легко прочесть саму формулу и убедиться в её корректности.

Ну это не индивидуальное преимущество данного метода, ибо и в "ручном" подсчёте можно составлять формулу по принципу: "число_символов_в_строке_без_учёта_спецификаторов + содержимое спецификаторов по отдельности + 1". Выйдет так же "прозрачно", как и в описанном приёме подсчёта через sizeof

Странно, что ты рассматриваешь альтернативу данному методу лишь в виде расчёта размера при помощи калькулятора и указания этого размера в виде целого числа. (считай это комментарием ко второму преимуществу)



Готовность к модификации.
При изменении форматного текста вносить изменения в формулу нужно только при добавлении новых спецификаторов или изменении уже имеющихся.
Для сравнения, при ручном подсчёте размер массива придётся пересчитывать при любом редактировании форматной строки.

Опять же, при ручном подсчёте так же можно использовать формулы. И если пользоваться редактором, что выводит количество выделенных символов, подсчитать новый размер не составит большого труда.


Грамотное использование стека.

Ну это тоже не является заслугой сугубо этого метода. Грамотно использовать стэк можно и при ручном расчёте точно так же, как и использовать стэк неграмотно в описанном тобой методе, подставляя в формулу рандомные значения.




Плохая читаемость кода.
Например, такой код:


new string[8 + 4];
format(string, sizeof(string), "Ваш ID: %d", playerid);

... занимает меньше места и может быть проще для восприятия, чем


static const fmt_str[] = "Ваш ID: %d";
new string[sizeof(fmt_str) + (-2 + 4)];
format(string, sizeof(string), fmt_str, playerid);

На самом деле "читаемость" кода - вещь субъективная. При достаточном опыте использования описываемого в данном уроке метода код из второго примера может перестать казаться сложным.

Ну да, на примере коротких строк код выглядит вполне нормально. Но попробуй, например, вот такой вариант:


static const fmt_str[] = "INSERT INTO `hotel` (mID,mOwned,mOwner,mX,mY,mZ,mCar,eX,eY,eZ,mLock,mMoney,mOplata,mVirt,mCarDrived,cX,cY,cZ,cRZ) VALUES (%d, 'None', %d, %f, %f, %f, %d, %f, %f, %f, 0, 2000, 1000, %d, 0, %f, %f, %f, %f)";
new string[sizeof(fmt_str) + (-2 + 4) + (-2 + 33) + (-2 + 11) + (-2 + 23) + (-2 + 14) + (-2 + 55) + (-2 + 44)];// Формула от балды написана. Суть не в ней
format(string, sizeof(string), fmt_str, HotelInfo[i][mID], HotelInfo[i][mOwner], HotelInfo[i][mEnter][0], HotelInfo[i][mEnter][1], HotelInfo[i][mEnter][2], HotelInfo[i][mCar], HotelInfo[i][mExit][0], HotelInfo[i][mExit][1], HotelInfo[i][mExit][2],HotelInfo[i][mVirt],cX,cY,cZ,cRZ);
И убери из запроса переменные: mOwner, [mExit][0] и cY.

stock SavePlayer(playerid)
{
static query[5000];
query = "UPDATE `accounts` SET ";
format(query, sizeof(query), "%sLvL=%d,", query, Player[playerid][pLevel]);
format(query, sizeof(query), "%sAdmin=%d,", query, Player[playerid][pAdmin]);
format(query, sizeof(query), "%sHelper=%d,", query, Player[playerid][pHelper]);
format(query, sizeof(query), "%spGuardCL=%d,", query, Player[playerid][pGuardCL]);
format(query, sizeof(query), "%sVip=%d,", query, Player[playerid][pVip]);
format(query, sizeof(query), "%sVipTime=%d,", query, Player[playerid][pVipTime]);
format(query, sizeof(query), "%sConnectTime=%d,", query, Player[playerid][pConnectTime]);
format(query, sizeof(query), "%sSex=%d,", query, Player[playerid][pSex]);
format(query, sizeof(query), "%sExp=%d,", query, Player[playerid][pExp]);
format(query, sizeof(query), "%sMoney=%d,", query, Player[playerid][pMoney]);
format(query, sizeof(query), "%sBankMoney=%d,", query, Player[playerid][pBankMoney]);
format(query, sizeof(query), "%sJailed=%d,", query, Player[playerid][pJailed]);
format(query, sizeof(query), "%sJailTime=%d,", query, Player[playerid][pJailTime]);
format(query, sizeof(query), "%sLeader=%d,", query, Player[playerid][pLeader]);
format(query, sizeof(query), "%sMember=%d,", query, Player[playerid][pMember]);
format(query, sizeof(query), "%sRank=%d,", query, Player[playerid][pRank]);
format(query, sizeof(query), "%sSkin=%d,", query, Player[playerid][pSkin]);
format(query, sizeof(query), "%sMutedTime=%d,", query, Player[playerid][pMutedTime]);
format(query, sizeof(query), "%sFMutedTime=%d,", query, Player[playerid][pFMutedTime]);
format(query, sizeof(query), "%sHealth=%f,", query, Player[playerid][pHealth]);
format(query, sizeof(query), "%sTut=%d,", query, Player[playerid][pTut]);
format(query, sizeof(query), "%sWarns=%d,", query, Player[playerid][pWarns]);
format(query, sizeof(query), "%sFWarns=%d,", query, Player[playerid][pFWarns]);
format(query, sizeof(query), "%sBlocks=%d,", query, Player[playerid][pBlocks]);
format(query, sizeof(query), "%sDonateMoney=%d,", query, Player[playerid][pDonateMoney]);
format(query, sizeof(query), "%sALLDonateMoney=%d,", query, Player[playerid][pALLDonateMoney]);
format(query, sizeof(query), "%sStylef=%d,", query, Player[playerid][pStylef]);
format(query, sizeof(query), "%sPiss=%d,", query, Player[playerid][pPiss]);
format(query, sizeof(query), "%sHunger=%d,", query, Player[playerid][pHunger]);
format(query, sizeof(query), "%sPit=%d,", query, Player[playerid][pPit]);
format(query, sizeof(query), "%sSleep=%d,", query, Player[playerid][pSleep]);
format(query, sizeof(query), "%sRadiation=%d,", query, Player[playerid][pRadiation]);
format(query, sizeof(query), "%sVirus=%d,", query, Player[playerid][pVirus]);
format(query, sizeof(query), "%sLastOnline=%d,", query, Player[playerid][pLastOnline]);
format(query, sizeof(query), "%sRegOnline=%d,", query, Player[playerid][pRegOnline]);
format(query, sizeof(query), "%sVampire=%d,", query, Player[playerid][pVampire]);
format(query, sizeof(query), "%sGunSkill_1=%d,", query, Player[playerid][pGunSkill][0]);
format(query, sizeof(query), "%sGunSkill_2=%d,", query, Player[playerid][pGunSkill][1]);
format(query, sizeof(query), "%sGunSkill_3=%d,", query, Player[playerid][pGunSkill][2]);
format(query, sizeof(query), "%sGunSkill_4=%d,", query, Player[playerid][pGunSkill][3]);
format(query, sizeof(query), "%sGunSkill_5=%d,", query, Player[playerid][pGunSkill][4]);
format(query, sizeof(query), "%sGunSkill_6=%d,", query, Player[playerid][pGunSkill][5]);
format(query, sizeof(query), "%sSpawn=%d,", query, Player[playerid][pSpawn]);
format(query, sizeof(query), "%sPosX=%f,", query, Player[playerid][pPosX]);
format(query, sizeof(query), "%sPosY=%f,", query, Player[playerid][pPosY]);
format(query, sizeof(query), "%sPosZ=%f,", query, Player[playerid][pPosZ]);
format(query, sizeof(query), "%sPosA=%f,", query, Player[playerid][pPosA]);
format(query, sizeof(query), "%sSpawnExit=%d,", query, Player[playerid][pSpawnExit]);
format(query, sizeof(query), "%sSlots=%d,", query, Player[playerid][pSlots]);
format(query, sizeof(query), "%sPack=%d,", query, Player[playerid][pPack]);
format(query, sizeof(query), "%sPupgrade=%d,", query, Player[playerid][gPupgrade]);
format(query, sizeof(query), "%sMask=%d,", query, Player[playerid][pMask]);
format(query, sizeof(query), "%sDiverSkill=%d,", query, Player[playerid][pDiverSkill]);
format(query, sizeof(query), "%sGuardCode=%d,", query, Player[playerid][pGuardCode]);
format(query, sizeof(query), "%sFlatKey=%d,", query, Player[playerid][pFlatKey]);
format(query, sizeof(query), "%s_Int_=%d,", query, Player[playerid][pInt]);
format(query, sizeof(query), "%sLocal=%d,", query, Player[playerid][pLocal]);
format(query, sizeof(query), "%sPhousekey=%d,", query, Player[playerid][pPhousekey]);
format(query, sizeof(query), "%sWeapon1=%d,", query, Player[playerid][Weapon1]);
format(query, sizeof(query), "%sWeapon1a=%d,", query, Player[playerid][Weapon1a]);
format(query, sizeof(query), "%sWeapon2=%d,", query, Player[playerid][Weapon2]);
format(query, sizeof(query), "%sWeapon2a=%d,", query, Player[playerid][Weapon2a]);
format(query, sizeof(query), "%sWeapon3=%d,", query, Player[playerid][Weapon3]);
format(query, sizeof(query), "%sWeapon3a=%d,", query, Player[playerid][Weapon3a]);
format(query, sizeof(query), "%sWeapon4=%d,", query, Player[playerid][Weapon4]);
format(query, sizeof(query), "%sWeapon4a=%d,", query, Player[playerid][Weapon4a]);
format(query, sizeof(query), "%sWeapon5=%d,", query, Player[playerid][Weapon5]);
format(query, sizeof(query), "%sWeapon5a=%d,", query, Player[playerid][Weapon5a]);
format(query, sizeof(query), "%sWeapon6=%d,", query, Player[playerid][Weapon6]);
format(query, sizeof(query), "%sWeapon6a=%d,", query, Player[playerid][Weapon6a]);
format(query, sizeof(query), "%sWeapon7=%d,", query, Player[playerid][Weapon7]);
format(query, sizeof(query), "%sWeapon7a=%d,", query, Player[playerid][Weapon7a]);
format(query, sizeof(query), "%sWeapon8=%d,", query, Player[playerid][Weapon8]);
format(query, sizeof(query), "%sWeapon8a=%d,", query, Player[playerid][Weapon8a]);
format(query, sizeof(query), "%sWeapon9=%d,", query, Player[playerid][Weapon9]);
format(query, sizeof(query), "%sWeapon9a=%d,", query, Player[playerid][Weapon9a]);
format(query, sizeof(query), "%sWeapon10=%d,", query, Player[playerid][Weapon10]);
format(query, sizeof(query), "%sWeapon10a=%d,", query, Player[playerid][Weapon10a]);
format(query, sizeof(query), "%sWeapon11=%d,", query, Player[playerid][Weapon11]);
format(query, sizeof(query), "%sWeapon11a=%d,", query, Player[playerid][Weapon11a]);
format(query, sizeof(query), "%sWeapon12=%d,", query, Player[playerid][Weapon12]);
format(query, sizeof(query), "%sWeapon12a=%d,", query, Player[playerid][Weapon12a]);
format(query, sizeof(query), "%sBarterSkil=%d,", query, Player[playerid][pBarterSkill]);
format(query, sizeof(query), "%sSurvSkill=%d,", query, Player[playerid][pSurvSkill]);
format(query, sizeof(query), "%sWeapSkill=%d,", query, Player[playerid][pWeapSkill]);
format(query, sizeof(query), "%sMedSkill=%d,", query, Player[playerid][pMedSkill]);
format(query, sizeof(query), "%sRepSkill=%d,", query, Player[playerid][pRepSkill]);
format(query, sizeof(query), "%sGuardClothes=%d", query, Player[playerid][pGuardClothes]);
format(query, sizeof(query), "%s WHERE Name='%s'", query, Player[playerid][pName]);
mysql_tquery(connectionHandle,query, "","");


query = "UPDATE `accounts` SET ";
for(new i; i < INVNUMBERS/2-1; i++)
format(query, sizeof(query), "%sPlayerInv_%d=%d,", query, i+1, Player[playerid][pPlayerInv][i]);
format(query, sizeof(query), "%sPlayerInv_%d=%d", query, INVNUMBERS/2, Player[playerid][pPlayerInv][INVNUMBERS/2-1]);
format(query, sizeof(query), "%s WHERE Name='%s'", query, Player[playerid][pName]);
mysql_tquery(connectionHandle,query, "","");


query = "UPDATE `accounts` SET ";
for(new i=INVNUMBERS/2; i < INVNUMBERS-1; i++)
format(query, sizeof(query), "%sPlayerInv_%d=%d,", query, i+1, Player[playerid][pPlayerInv][i]);
format(query, sizeof(query), "%sPlayerInv_%d=%d", query, INVNUMBERS, Player[playerid][pPlayerInv][INVNUMBERS-1]);
format(query, sizeof(query), "%s WHERE Name='%s'", query, Player[playerid][pName]);
mysql_tquery(connectionHandle,query, "","");


query = "UPDATE `accounts` SET ";
for(new i; i < IDKVEST; i++)
{
format(query, sizeof(query), "%sSaveKvest_%d=%d,", query, i+1, Player[playerid][pSaveKvest][i]);
}
for(new i; i < 20; i++)
{
format(query, sizeof(query), "%sPlayerInv_%d=%d,", query, i+1, Player[playerid][pPlayerGMP][i]);
}
format(query, sizeof(query), "%sOtkatgun=%d,", query, Player[playerid][pOtkatgun]);
format(query, sizeof(query), "%sHeadValue=%d,", query, Player[playerid][pHeadValue]);
format(query, sizeof(query), "%sFishki=%d,", query, Player[playerid][pFishki]);
format(query, sizeof(query), "%sTimequest=%d,", query, Player[playerid][pTimequest]);
format(query, sizeof(query), "%sInfoquest=%d,", query, Player[playerid][pInfoquest]);
format(query, sizeof(query), "%sNaruch=%d,", query, Player[playerid][pNaruch]);
format(query, sizeof(query), "%sPame='%s',", query, Player[playerid][pPame]);
format(query, sizeof(query), "%sGul=%d", query, Player[playerid][pGul]);
format(query, sizeof(query), "%s WHERE Name='%s'", query, Player[playerid][pName]);
mysql_tquery(connectionHandle,query, "","");
return 1;
}
Чем больше спецификаторов в строке и чем больше строк, тем нереальней становится нормальная работа с кодом. И дело тут не в привычке, а в том, что довольно трудно сопоставить 13 спецификатор из строки какой-то определённой переменной, ибо приходится по всему экрану глазами водить в поисках нужных данных.


Трудоёмкость.
И ежу понятно, что бездумно написать "new string[145];" куда проще, чем составлять формулы.
В принципе то же самое относится и к ручному подсчёту с помощью калькулятора, да и к любому другому методу подсчёта вообще. Зачем что-то рассчитывать, если можно обойтись максимальной длиной строки ("145" или "MAX_CHATBUBBLE_LENGTH + 1" для SendClientMessage) или ещё чем-то подобным?

Опять же, ты довольно однобоко рассматриваешь альтернативы :) Но об этом уже выше сказал

Daniel_Cortez
09.05.2017, 15:30
Да, пожалуй, составлять сравнение в 4 часа ночи было не самой лучшей идеей.


Ну это не индивидуальное преимущество данного метода, ибо и в "ручном" подсчёте можно составлять формулу по принципу: "число_символов_в_строке_без_учёта_спецификаторов + содержимое спецификаторов по отдельности + 1". Выйдет так же "прозрачно", как и в описанном приёме подсчёта через sizeof
Добавил замечания о ручном подсчёте с использованием формул в 1-й и 2-й пункты. Правда, не уверен, что "ручной подсчёт" является самым подходящим названием, но пока что оставлю так.



Странно, что ты рассматриваешь альтернативу данному методу лишь в виде расчёта размера при помощи калькулятора и указания этого размера в виде целого числа. (считай это комментарием ко второму преимуществу)
Если рассматривать ручной подсчёт с использованием формул, то разница между таким способом и описываемым мной сводится лишь к явному объявлению форматной строки в виде поименованного массива и использованию sizeof для автоматического подсчёта его размера.
наверное, именно поэтому я и не пытался сделать сравнение с этим способом. Но, как я уже сказал ранее, сейчас я добавил о нём заметки.



Ну это тоже не является заслугой сугубо этого метода. Грамотно использовать стэк можно и при ручном расчёте точно так же, как и использовать стэк неграмотно в описанном тобой методе, подставляя в формулу рандомные значения.
Да, действительно. Изначально я планировал сделать сравнение с отсутствием подсчёта вообще, но потом переключился на сравнение с ручным подсчётом, а об остатках от старого текста благополучно забыл. Сказывается ночное время суток.
Сейчас я уже перенёс этот пункт в список особенностей.




stock SavePlayer(playerid)
{
static query[5000];
query = "UPDATE `accounts` SET ";
format(query, sizeof(query), "%sLvL=%d,", query, Player[playerid][pLevel]);
format(query, sizeof(query), "%sAdmin=%d,", query, Player[playerid][pAdmin]);
format(query, sizeof(query), "%sHelper=%d,", query, Player[playerid][pHelper]);
format(query, sizeof(query), "%spGuardCL=%d,", query, Player[playerid][pGuardCL]);
format(query, sizeof(query), "%sVip=%d,", query, Player[playerid][pVip]);
format(query, sizeof(query), "%sVipTime=%d,", query, Player[playerid][pVipTime]);
format(query, sizeof(query), "%sConnectTime=%d,", query, Player[playerid][pConnectTime]);
format(query, sizeof(query), "%sSex=%d,", query, Player[playerid][pSex]);
format(query, sizeof(query), "%sExp=%d,", query, Player[playerid][pExp]);
format(query, sizeof(query), "%sMoney=%d,", query, Player[playerid][pMoney]);
format(query, sizeof(query), "%sBankMoney=%d,", query, Player[playerid][pBankMoney]);
format(query, sizeof(query), "%sJailed=%d,", query, Player[playerid][pJailed]);
format(query, sizeof(query), "%sJailTime=%d,", query, Player[playerid][pJailTime]);
format(query, sizeof(query), "%sLeader=%d,", query, Player[playerid][pLeader]);
format(query, sizeof(query), "%sMember=%d,", query, Player[playerid][pMember]);
format(query, sizeof(query), "%sRank=%d,", query, Player[playerid][pRank]);
format(query, sizeof(query), "%sSkin=%d,", query, Player[playerid][pSkin]);
format(query, sizeof(query), "%sMutedTime=%d,", query, Player[playerid][pMutedTime]);
format(query, sizeof(query), "%sFMutedTime=%d,", query, Player[playerid][pFMutedTime]);
format(query, sizeof(query), "%sHealth=%f,", query, Player[playerid][pHealth]);
format(query, sizeof(query), "%sTut=%d,", query, Player[playerid][pTut]);
format(query, sizeof(query), "%sWarns=%d,", query, Player[playerid][pWarns]);
format(query, sizeof(query), "%sFWarns=%d,", query, Player[playerid][pFWarns]);
format(query, sizeof(query), "%sBlocks=%d,", query, Player[playerid][pBlocks]);
format(query, sizeof(query), "%sDonateMoney=%d,", query, Player[playerid][pDonateMoney]);
format(query, sizeof(query), "%sALLDonateMoney=%d,", query, Player[playerid][pALLDonateMoney]);
format(query, sizeof(query), "%sStylef=%d,", query, Player[playerid][pStylef]);
format(query, sizeof(query), "%sPiss=%d,", query, Player[playerid][pPiss]);
format(query, sizeof(query), "%sHunger=%d,", query, Player[playerid][pHunger]);
format(query, sizeof(query), "%sPit=%d,", query, Player[playerid][pPit]);
format(query, sizeof(query), "%sSleep=%d,", query, Player[playerid][pSleep]);
format(query, sizeof(query), "%sRadiation=%d,", query, Player[playerid][pRadiation]);
format(query, sizeof(query), "%sVirus=%d,", query, Player[playerid][pVirus]);
format(query, sizeof(query), "%sLastOnline=%d,", query, Player[playerid][pLastOnline]);
format(query, sizeof(query), "%sRegOnline=%d,", query, Player[playerid][pRegOnline]);
format(query, sizeof(query), "%sVampire=%d,", query, Player[playerid][pVampire]);
format(query, sizeof(query), "%sGunSkill_1=%d,", query, Player[playerid][pGunSkill][0]);
format(query, sizeof(query), "%sGunSkill_2=%d,", query, Player[playerid][pGunSkill][1]);
format(query, sizeof(query), "%sGunSkill_3=%d,", query, Player[playerid][pGunSkill][2]);
format(query, sizeof(query), "%sGunSkill_4=%d,", query, Player[playerid][pGunSkill][3]);
format(query, sizeof(query), "%sGunSkill_5=%d,", query, Player[playerid][pGunSkill][4]);
format(query, sizeof(query), "%sGunSkill_6=%d,", query, Player[playerid][pGunSkill][5]);
format(query, sizeof(query), "%sSpawn=%d,", query, Player[playerid][pSpawn]);
format(query, sizeof(query), "%sPosX=%f,", query, Player[playerid][pPosX]);
format(query, sizeof(query), "%sPosY=%f,", query, Player[playerid][pPosY]);
format(query, sizeof(query), "%sPosZ=%f,", query, Player[playerid][pPosZ]);
format(query, sizeof(query), "%sPosA=%f,", query, Player[playerid][pPosA]);
format(query, sizeof(query), "%sSpawnExit=%d,", query, Player[playerid][pSpawnExit]);
format(query, sizeof(query), "%sSlots=%d,", query, Player[playerid][pSlots]);
format(query, sizeof(query), "%sPack=%d,", query, Player[playerid][pPack]);
format(query, sizeof(query), "%sPupgrade=%d,", query, Player[playerid][gPupgrade]);
format(query, sizeof(query), "%sMask=%d,", query, Player[playerid][pMask]);
format(query, sizeof(query), "%sDiverSkill=%d,", query, Player[playerid][pDiverSkill]);
format(query, sizeof(query), "%sGuardCode=%d,", query, Player[playerid][pGuardCode]);
format(query, sizeof(query), "%sFlatKey=%d,", query, Player[playerid][pFlatKey]);
format(query, sizeof(query), "%s_Int_=%d,", query, Player[playerid][pInt]);
format(query, sizeof(query), "%sLocal=%d,", query, Player[playerid][pLocal]);
format(query, sizeof(query), "%sPhousekey=%d,", query, Player[playerid][pPhousekey]);
format(query, sizeof(query), "%sWeapon1=%d,", query, Player[playerid][Weapon1]);
format(query, sizeof(query), "%sWeapon1a=%d,", query, Player[playerid][Weapon1a]);
format(query, sizeof(query), "%sWeapon2=%d,", query, Player[playerid][Weapon2]);
format(query, sizeof(query), "%sWeapon2a=%d,", query, Player[playerid][Weapon2a]);
format(query, sizeof(query), "%sWeapon3=%d,", query, Player[playerid][Weapon3]);
format(query, sizeof(query), "%sWeapon3a=%d,", query, Player[playerid][Weapon3a]);
format(query, sizeof(query), "%sWeapon4=%d,", query, Player[playerid][Weapon4]);
format(query, sizeof(query), "%sWeapon4a=%d,", query, Player[playerid][Weapon4a]);
format(query, sizeof(query), "%sWeapon5=%d,", query, Player[playerid][Weapon5]);
format(query, sizeof(query), "%sWeapon5a=%d,", query, Player[playerid][Weapon5a]);
format(query, sizeof(query), "%sWeapon6=%d,", query, Player[playerid][Weapon6]);
format(query, sizeof(query), "%sWeapon6a=%d,", query, Player[playerid][Weapon6a]);
format(query, sizeof(query), "%sWeapon7=%d,", query, Player[playerid][Weapon7]);
format(query, sizeof(query), "%sWeapon7a=%d,", query, Player[playerid][Weapon7a]);
format(query, sizeof(query), "%sWeapon8=%d,", query, Player[playerid][Weapon8]);
format(query, sizeof(query), "%sWeapon8a=%d,", query, Player[playerid][Weapon8a]);
format(query, sizeof(query), "%sWeapon9=%d,", query, Player[playerid][Weapon9]);
format(query, sizeof(query), "%sWeapon9a=%d,", query, Player[playerid][Weapon9a]);
format(query, sizeof(query), "%sWeapon10=%d,", query, Player[playerid][Weapon10]);
format(query, sizeof(query), "%sWeapon10a=%d,", query, Player[playerid][Weapon10a]);
format(query, sizeof(query), "%sWeapon11=%d,", query, Player[playerid][Weapon11]);
format(query, sizeof(query), "%sWeapon11a=%d,", query, Player[playerid][Weapon11a]);
format(query, sizeof(query), "%sWeapon12=%d,", query, Player[playerid][Weapon12]);
format(query, sizeof(query), "%sWeapon12a=%d,", query, Player[playerid][Weapon12a]);
format(query, sizeof(query), "%sBarterSkil=%d,", query, Player[playerid][pBarterSkill]);
format(query, sizeof(query), "%sSurvSkill=%d,", query, Player[playerid][pSurvSkill]);
format(query, sizeof(query), "%sWeapSkill=%d,", query, Player[playerid][pWeapSkill]);
format(query, sizeof(query), "%sMedSkill=%d,", query, Player[playerid][pMedSkill]);
format(query, sizeof(query), "%sRepSkill=%d,", query, Player[playerid][pRepSkill]);
format(query, sizeof(query), "%sGuardClothes=%d", query, Player[playerid][pGuardClothes]);
format(query, sizeof(query), "%s WHERE Name='%s'", query, Player[playerid][pName]);
mysql_tquery(connectionHandle,query, "","");


query = "UPDATE `accounts` SET ";
for(new i; i < INVNUMBERS/2-1; i++)
format(query, sizeof(query), "%sPlayerInv_%d=%d,", query, i+1, Player[playerid][pPlayerInv][i]);
format(query, sizeof(query), "%sPlayerInv_%d=%d", query, INVNUMBERS/2, Player[playerid][pPlayerInv][INVNUMBERS/2-1]);
format(query, sizeof(query), "%s WHERE Name='%s'", query, Player[playerid][pName]);
mysql_tquery(connectionHandle,query, "","");


query = "UPDATE `accounts` SET ";
for(new i=INVNUMBERS/2; i < INVNUMBERS-1; i++)
format(query, sizeof(query), "%sPlayerInv_%d=%d,", query, i+1, Player[playerid][pPlayerInv][i]);
format(query, sizeof(query), "%sPlayerInv_%d=%d", query, INVNUMBERS, Player[playerid][pPlayerInv][INVNUMBERS-1]);
format(query, sizeof(query), "%s WHERE Name='%s'", query, Player[playerid][pName]);
mysql_tquery(connectionHandle,query, "","");


query = "UPDATE `accounts` SET ";
for(new i; i < IDKVEST; i++)
{
format(query, sizeof(query), "%sSaveKvest_%d=%d,", query, i+1, Player[playerid][pSaveKvest][i]);
}
for(new i; i < 20; i++)
{
format(query, sizeof(query), "%sPlayerInv_%d=%d,", query, i+1, Player[playerid][pPlayerGMP][i]);
}
format(query, sizeof(query), "%sOtkatgun=%d,", query, Player[playerid][pOtkatgun]);
format(query, sizeof(query), "%sHeadValue=%d,", query, Player[playerid][pHeadValue]);
format(query, sizeof(query), "%sFishki=%d,", query, Player[playerid][pFishki]);
format(query, sizeof(query), "%sTimequest=%d,", query, Player[playerid][pTimequest]);
format(query, sizeof(query), "%sInfoquest=%d,", query, Player[playerid][pInfoquest]);
format(query, sizeof(query), "%sNaruch=%d,", query, Player[playerid][pNaruch]);
format(query, sizeof(query), "%sPame='%s',", query, Player[playerid][pPame]);
format(query, sizeof(query), "%sGul=%d", query, Player[playerid][pGul]);
format(query, sizeof(query), "%s WHERE Name='%s'", query, Player[playerid][pName]);
mysql_tquery(connectionHandle,query, "","");
return 1;
}
Чем больше спецификаторов в строке и чем больше строк, тем нереальней становится нормальная работа с кодом. И дело тут не в привычке, а в том, что довольно трудно сопоставить 13 спецификатор из строки какой-то определённой переменной, ибо приходится по всему экрану глазами водить в поисках нужных данных.
Ну это уже совсем крайность. Понятное дело, в таком случае процесс подсчёта будет слишком трудоёмким, с формулами или без. Но если нужно проконтролировать расход стека, проще рассчитать всё опытным путём: специально составить аккаунт с данными, занимающими в строковом виде больше всего символов, и посмотреть длину сформатированной строки. А потом оставить пару комментариев в этой функции и в структуре pInfo для напоминания, что нужно пересчитать размер форматного буфера при изменении структуры или набора сохраняемых данных, и заодно закомментировать где-нибудь рядом тестовый набор данных, чтобы не составлять его каждый раз заново.



Опять же, ты довольно однобоко рассматриваешь альтернативы :) Но об этом уже выше сказал
А здесь-то я что не так сделал?

DeimoS
09.05.2017, 16:02
Если рассматривать ручной подсчёт с использованием формул, то разница между таким способом и описываемым мной сводится лишь к явному объявлению форматной строки в виде поименованного массива и использованию sizeof для автоматического подсчёта его размера.
Ну вот именно поэтому мне данный метод и не нравится. Особенно когда, например, массив объявляют в начале команды, а format, гд массив используется, находится в середине или конце. Не знаю как остальным, но мне это доставляет дикие неудобства, ибо приходится не просто водить взглядом по одной строке, а пол экрана приходится контролировать и держать в памяти примерное расположение нужных частей кода.




Ну это уже совсем крайность. Понятное дело, в таком случае процесс подсчёта будет слишком трудоёмким, с формулами или без.

Без отдельного массива всё будет более наглядно, если и сам запрос в порядок привести и форматирование более адекватно прописать. Ну или делать так, как я в статье о системе аккаунтов расписывал: для каждой переменной свой format, подсчёт размера для каждого format отдельно (оставляя комментарий о том, сколько занимает сам текст и сколько занимают данные, что в текст вставляются) и, собственно, составление одной большой формулы, в которой будут перечислены все строки по отдельности

stock SaveAccount(playerid)
{
new
query_string[(21) + (16+10)+ (20+MAX_PLAYER_NAME-4) + (16+MAX_PLAYER_PASSWORD) + 1] = "UPDATE `accounts` SET";// (21)
// Сначала те части запроса, которые никогда не будут меняться ( "UPDATE `accounts` SET" и "%s WHERE `id` = '%d'" )
// А потом уже все остальные, начиная с верхнего "%s `player_name` = '%s'," и дальше

format(query_string, sizeof(query_string), "%s `player_name` = '%s',", query_string, pInfo[playerid][pName]);// (20+MAX_PLAYER_NAME-4)
format(query_string, sizeof(query_string), "%s `password` = '%s'", query_string, pInfo[playerid][pPassword]);// (16+MAX_PLAYER_PASSWORD)

format(query_string, sizeof(query_string), "%s WHERE `id` = '%d'", query_string, pInfo[playerid][pID]);// (16+10)
mysql_function_query(mysql_connect_ID, query_string, false, "", "");
return 1;
}
Такой подход, конечно, не самый лучший в плане производительности и для миллисекундодрочеров не пойдёт, но, как по мне, он является самым гибким и легко изменяемым для строк, которые целиком состоят из форматирования, ибо благодаря комментариям более наглядно видно какую часть формулы нужно изменять и можно без лишних трудностей добавлять/убирать дополнительные строки в запросе, не рискуя при этом удалить что-то лишнее или поместить добавленную переменную не на то место, на котором находится спецификатор в строке (может тоже статью написать на эту тему, лол).


А здесь-то я что не так сделал?

Ну я имел ввиду то, что ты опять сравниваешь лишь описанный тобой метод и ручной подсчёт на калькуляторе, забывая о других альтернативах. Это странно выглядит в пункте, который раскрывает плюсы и минусы описываемого тобой метода. Как по мне, этот пункт подразумевает сравнение со всеми альтернативами (ну или хотя бы более-менее распространёнными), а не только с одной из самых плохих.


Правда, не уверен, что "ручной подсчёт" является самым подходящим названием, но пока что оставлю так.

Ну, по сути, это ручной подсчёт с составлением формулы же. То, что, например, я использую для подсчёта возможности редактора, не говорит ни о чём, ибо это, скорее, просто упрощение процесса ручного подсчёта, как и в случае с использованием калькулятора вместо самостоятельного подсчёта.
Хотя даже с использованием функции редактора я сам потом ещё правлю результат, убирая учёт спецификаторов и спецсимволов, дабы формула была более компактной

Daniel_Cortez
09.05.2017, 17:32
Ну вот именно поэтому мне данный метод и не нравится. Особенно когда, например, массив объявляют в начале команды, а format, гд массив используется, находится в середине или конце. Не знаю как остальным, но мне это доставляет дикие неудобства, ибо приходится не просто водить взглядом по одной строке, а пол экрана приходится контролировать и держать в памяти примерное расположение нужных частей кода.
Если должным образом назвать массивы с форматными строками, то не придётся запоминать, где и что лежит - всё будет понятно из названия.
Например, в том же случае с форматированием запроса можно назвать форматные строки "fmt_str_pname", "fmt_str_ppasshash", "fmt_str_plevel" и т.п.
Но я всё же добавил в недостатки вынесение форматной строки в отдельный массив.



может тоже статью написать на эту тему, лол
Если в ней описать инструмент для подсчёта длины строк (ты вроде сам говорил, это что-то встроенное в ST3? но только этим вряд ли можно обойтись) и привести конкретные примеры, где этот подход лучше применим, то почему бы и нет?



Ну я имел ввиду то, что ты опять сравниваешь лишь описанный тобой метод и ручной подсчёт на калькуляторе, забывая о других альтернативах.
Так я ж с самого начала написал в том пункте, что он относится и ко всем другим методам подсчёта. -_-


В принципе то же самое относится и к ручному подсчёту с помощью калькулятора, да и к любому другому методу подсчёта вообще.

И я так понимаю, сия претензия была именно к этому пункту, раз ты процитировал именно его.

DeimoS
09.05.2017, 18:36
Если должным образом назвать массивы с форматными строками, то не придётся запоминать, где и что лежит - всё будет понятно из названия.
Например, в том же случае с форматированием запроса можно назвать форматные строки "fmt_str_pname", "fmt_str_ppasshash", "fmt_str_plevel" и т.п.
Но я всё же добавил в недостатки вынесение форматной строки в отдельный массив.

Не, речь не о том, что непонятно откуда берётся массив и как его найти. Речь о том, что, например, для сверки положения каждого спецификатора с положением переменной для этого спецификатора нужно, в лучшем случае, по всему экрану взглядом водить, а может даже и вообще скроллить код, ибо массив и format разделяет большое число строк.