Баг в PAWNO, энуменаторы.
#1

В общем, месяц назад делал регистрацию для сервера, в энуменатор информации игрока записал ник, пароль, электронную почту, пол, уровень, деньги и расу.
Из них текстовыми являются ник, пароль и раса. Максимальное значение расы - 15 символ. Ну я записал в массив 16, учитывая нуль-терминатор. И что-то решил изменить массив с 16 на 15, проверить кое-что. Но ошибся и поставил массив 1. Когда я проверил - я был удивлён, в переменную записалось значение из 15 символов. Я неделю мучился и искал что может быть не так. И сегодня я решил поменять порядок расположения: ник, пароль, электронная почта, раса, пол, деньги. И вот тут с массивом равным 1 не прокатило, пришлось ставить 16.
Вот ещё, что заметил.
От положения текстовой переменной в в энуменаторе зависит как она будет себя ввести, когда в неё запишут какое-то значение (это в том случае, если размер массива указан меньше, чем надо). Если текстовая переменная находится после всех (именно после текстовых, а не последняя в энуменаторе), то, похоже, нуль-символ не учитывается, но тогда значение какой-либо целочисленной переменной искажается. Если её потом поменять местом с любой текстовой - происходит склеивание строк из-за отсутствия нуль-терминатора.

Примеры:

Корректный вариант (массивы указаны верно и текстовая переменная находится в конце энуменатора, другие в центре):

Code:
#include <a_samp>

enum test
{
        ext,
        ext1,
        etc[7],
        etc1[5],
        ext2,
        ext3,
        etc2[9],
}
new testt[test];

main()
{
        print("\n----------------------------------");
        print(" Blank Gamemode by your name here");
        print("----------------------------------\n");
}

public OnGameModeInit()
{
        testt[ext] = 1111;
        testt[ext1] = 1;
        testt[etc][0] = EOS;
        strins(testt[etc], "123456", 0);
        testt[etc1][0] = EOS;
        strins(testt[etc1], "1234", 0);
        testt[etc2][0] = EOS;
        strins(testt[etc2], "12345678", 0);
        testt[ext2] = 0;
        testt[ext3] = 1341234;
        printf("%d, %d, %s, %s, %d, %d, %s", testt[ext], testt[ext1], testt[etc], testt[etc1], testt[ext2], testt[ext3], testt[etc2]);
        return 1;
}
Итог:

Code:
[22:42:56] 1111, 1, 123456, 1234, 0, 1341234, 12345678
[22:42:56] 
----------------------------------
[22:42:56]  Blank Gamemode by your name here
[22:42:56] ----------------------------------

[22:42:56] Number of vehicle models: 0
Указываем у последней переменной массив равный 2:

Code:
#include <a_samp>

enum test
{
        ext,
        ext1,
        etc[7],
        etc1[5],
        ext2,
        ext3,
        etc2[2],
}
new testt[test];

main()
{
        print("\n----------------------------------");
        print(" Blank Gamemode by your name here");
        print("----------------------------------\n");
}

public OnGameModeInit()
{
        testt[ext] = 1111;
        testt[ext1] = 1;
        testt[etc][0] = EOS;
        strins(testt[etc], "123456", 0);
        testt[etc1][0] = EOS;
        strins(testt[etc1], "1234", 0);
        testt[etc2][0] = EOS;
        strins(testt[etc2], "12345678", 0);
        testt[ext2] = 0;
        testt[ext3] = 1341234;
        printf("%d, %d, %s, %s, %d, %d, %s", testt[ext], testt[ext1], testt[etc], testt[etc1], testt[ext2], testt[ext3], testt[etc2]);
        return 1;
}
В итоге видим, что переменная нормально отобразилось, но появилась "отбросочная строка", та же, только там проигнорированы первые 2 символа. Странно, да? Ведь должна было просто не отобразится строка, либо же не полностью. Если тестить в игре - то в переменную разумеется запишется только значение 1 строки, а вот то что мы видим на 2 строке - не будет, ибо, допустим функция SendClientMessage выводит лишь 1 строку. В консоли, как видим возможно, что странно.

Code:
[22:44:12] ---------------
[22:44:12]   Loaded 0 filterscripts.

[22:44:12] 1111, 1, 123456, 1234, 0, 1341234, 12345678
[22:44:12] 345678
[22:44:12]  Blank Gamemode by your name here
[22:44:12] ----------------------------------

[22:44:12] Number of vehicle models: 0
Теперь ставим эту переменную с массивом 2 в конец текстовых переменных.

Code:
#include <a_samp>

enum test
{
        ext,
        ext1,
        etc[7],
        etc1[5],
        etc2[2],
        ext2,
        ext3,
}
new testt[test];

main()
{
        print("\n----------------------------------");
        print(" Blank Gamemode by your name here");
        print("----------------------------------\n");
}

public OnGameModeInit()
{
        testt[ext] = 1111;
        testt[ext1] = 1;
        testt[etc][0] = EOS;
        strins(testt[etc], "123456", 0);
        testt[etc1][0] = EOS;
        strins(testt[etc1], "1234", 0);
        testt[etc2][0] = EOS;
        strins(testt[etc2], "12345678", 0);
        testt[ext2] = 0;
        testt[ext3] = 1341234;
        printf("%d, %d, %s, %s, %d, %d, %s", testt[ext], testt[ext1], testt[etc], testt[etc1], testt[ext2], testt[ext3], testt[etc2]);
        return 1;
}
Как мы видим отобразилось 2 первых символа, логично, но опять же присутствует "отбросочная строка". Также, тестируя в игре - у меня исказилась целочисленная переменная.

Code:
[22:48:25] ---------------
[22:48:25]   Loaded 0 filterscripts.

[22:48:25] 1111, 1, 123456, 1234, 0, 1341234, 12
[22:48:25] 5678
[22:48:25]  Blank Gamemode by your name here
[22:48:25] ----------------------------------

[22:48:25] Number of vehicle models: 0
Ставим эту переменную по середине текстовых, опять же с размером массива 2:

Code:
#include <a_samp>

enum test
{
	ext,
	ext1,
	etc[7],
	etc2[2],
	etc1[5],
	ext2,
	ext3,
}
new testt[test];

main()
{
	print("\n----------------------------------");
	print(" Blank Gamemode by your name here");
	print("----------------------------------\n");
}

public OnGameModeInit()
{
	testt[ext] = 1111;
	testt[ext1] = 1;
	testt[etc][0] = EOS;
	strins(testt[etc], "123456", 0);
	testt[etc1][0] = EOS;
	strins(testt[etc1], "1234", 0);
	testt[etc2][0] = EOS;
	strins(testt[etc2], "12345678", 0);
	testt[ext2] = 0;
	testt[ext3] = 1341234;
	printf("%d, %d, %s, %s, %d, %d, %s", testt[ext], testt[ext1], testt[etc], testt[etc1], testt[ext2], testt[ext3], testt[etc2]);
	return 1;
}
Склеилась другая текстовая переменная:

Code:
[17:36:50] ---------------
[17:36:50]   Loaded 0 filterscripts.

[17:36:50] 1111, 1, 123456, 34567, 0, 1341234, 1234567
[17:36:50] 
----------------------------------
[17:36:50]  Blank Gamemode by your name here
[17:36:50] ----------------------------------

[17:36:50] Number of vehicle models: 0
Вот такие вот дела.
Reply
#2

Для строк в enum нужно указывать максимальный размер массива (в данном случае - это параметр maxlength) вручную, ибо sizeof вернёт размер первого измерения переданного массива. Но здесь мы имеем дело с функцией strins, в которой значение maxlength ни на что не влияет (баг). Исправление этой функции, кстати, есть в fixes.inc.
Reply
#3

Но почему же тогда результат менялся в зависимости от местонахождения переменной в энуменаторе?
Reply
#4

Quote:
Originally Posted by Danger228
View Post
Но почему же тогда результат менялся в зависимости от местонахождения переменной в энуменаторе?
Что конкретно ты имеешь ввиду? Сделай более наглядные примеры и убери лишний код - это поможет разобраться.
Reply
#5

Code:
public OnGameModeInit()
{
        testt[ext] = 1111;
        testt[ext1] = 1;
        testt[etc][0] = EOS;
        strins(testt[etc], "123456", 0);
        testt[etc1][0] = EOS;
        strins(testt[etc1], "1234", 0);
        testt[etc2][0] = EOS;
        strins(testt[etc2], "12345678", 0);
        testt[ext2] = 0;
        testt[ext3] = 1341234;
        printf("%d, %d, %s, %s, %d, %d, %s", testt[ext], testt[ext1], testt[etc], testt[etc1], testt[ext2], testt[ext3], testt[etc2]);
        return 1;
}
Таким образом приравниваем и в последующем выводим переменные, которые объявим. Правильный размер etc2 - 9, ибо 8 символов + нуль-терминатор.

1) 1 текстовую переменную укажем последней в enum, другие текстовые - по середине
Code:
enum test
{
        ext,
        ext1,
        etc[7],
        etc1[5],
        ext2,
        ext3,
        etc2[9],
}
Итог:
Code:
[22:42:56] 1111, 1, 123456, 1234, 0, 1341234, 12345678
2) Уменьшим этой переменной размер массива до 2:
Code:
enum test
{
        ext,
        ext1,
        etc[7],
        etc1[5],
        ext2,
        ext3,
        etc2[2],
}
Таким образом видим, что всё отобразилось в норме, но есть "отбросочная строка". В игре бы - её не было бы, именно поэтому я мог указывать размер массива даже 1.
Code:
[22:44:12] 1111, 1, 123456, 1234, 0, 1341234, 12345678
[22:44:12] 345678
3) Теперь её перенесем в конец текстовых переменных, но не в конец enum, опять же, с размером массива 2:
Code:
enum test
{
        ext,
        ext1,
        etc[7],
        etc1[5],
        etc2[2],
        ext2,
        ext3,
}
Уже другой результат, отобразились первые 2 символа, как и должно, но присутствует "отбросочная строка":
Code:
[22:48:25] 1111, 1, 123456, 1234, 0, 1341234, 12
[22:48:25] 5678
4) Ставим переменную по середине текстовых, опять же, с размером массива 2:
Code:
enum test
{
	ext,
	ext1,
	etc[7],
	etc2[2],
	etc1[5],
	ext2,
	ext3,
}
Всё нормально отобразилось, но пропал последний символ и значение четвёртой переменной (etc1) склеилась с кусками нашей переменной с массивом 2.
Code:
[17:36:50] 1111, 1, 123456, 34567, 0, 1341234, 1234567
Надеюсь понятно изложил
Reply
#6

Я имел ввиду меньше текста и больше наглядности...
Например так:
PHP Code:
#include <a_samp>
enum test
{
    
arr1[6],
    
val1,
    
val2,
    
arr2[6],
}
new var[
test];
main() {
    
strins(var[arr1], "hello"0);
    
strins(var[arr2], "world"0);
    var[
val1] = 99;
    var[
val2] = 123456;
    
printf("var[arr1] = %s (%s)", var[arr1], "hello");
    
printf("var[val1] = %d (%d)", var[val1], 99);
    
printf("var[val2] = %d (%d)", var[val2], 123456);
    
printf("var[arr2] = %s (%s)", var[arr2], "world");

Здесь сразу видно что чему равно и какие значения ожидалось увидеть, также для строк нагляднее использовать буквы, а не цифры.
Вот результаты:
PHP Code:
var[arr1] = hello (hello)
var[
val1] = 99 (99)
var[
val2] = 123456 (123456)
var[
arr2] = world (world
PHP Code:
var[arr1] = hello (hello)
var[
val1] = 99 (99)
var[
val2] = 123456 (123456)
var[
arr2] = world (world
PHP Code:
var[arr1] = hello (hello)
var[
val1] = 99 (99)
var[
val2] = 123456 (123456)
var[
arr2] = woc@(world
PHP Code:
var[arr1] = rld (hello)
var[
val1] = 99 (99)
var[
val2] = 123456 (123456)
var[
arr2] = world (world
Ну и вопрос: что тут непонятного? Ты работаешь с функцией, у которой нет проверки выхода за пределы её размера, какой работы ты от неё ожидаешь? Используй strcat, format или подключи fixes.inc.
Reply
#7

Какая разница, значение переменной менялось в зависимости от местоположения в энуменаторе. И вроде бы тогда у меня был подключен fixes, сейчас да, не подключен, но суть одна, это явно не из-за баганной функции strins.
Reply
#8

Quote:
Originally Posted by Danger228
View Post
Какая разница, значение переменной менялось в зависимости от местоположения в энуменаторе. И вроде бы тогда у меня был подключен fixes, сейчас да, не подключен, но суть одна, это явно не из-за баганной функции strins.
Это именно из-за этого. Зачем ты спрашиваешь вообще, если не принимаешь ответ? Взял бы да проверил...

PHP Code:
enum test
{
    
arr2[2],
    
arr1[6],
    
val1,
    
val2,
}
new var[
test];
main() {
    
strcat(var[arr1], "hello"6);
    
strcat(var[arr2], "world"2);
    var[
val1] = 99;
    var[
val2] = 123456;
    
printf("var[arr1] = %s (%s)", var[arr1], "hello");
    
printf("var[val1] = %d (%d)", var[val1], 99);
    
printf("var[val2] = %d (%d)", var[val2], 123456);
    
printf("var[arr2] = %s (%s)", var[arr2], "world");

Результат:
PHP Code:
var[arr1] = hello (hello)
var[
val1] = 99 (99)
var[
val2] = 123456 (123456)
var[
arr2] = (world
Reply
#9

Хм... Странно, что на это влияло местоположение в энуменаторе.
+ rep дал)
Спасибо за помощь)
Reply


Forum Jump:


Users browsing this thread: 1 Guest(s)