PDA

Просмотр полной версии : [Вопрос] Несколько вопросов



PawnoNoob
02.04.2016, 20:56
Приветствую! У меня, как у новичка в Pawn, есть несколько вопросов относительно программирования, ответы на которых, к сожалению, я не смог найти в поисковике:
1. После того, как игрок зарегистрировался на сервере, его телепортирует в интерьер для выбора внешности. Всё это "дело" выполнено на TextDraw. После того, как его телепортирует в интерьер, ему "присваивается" виртуальный мир, равный его id (игрок с id 1, значит вирт. мир при выборе внешности равен 1). Всё это "дело" сделано в виде stock, но не в этом суть. После нажатия кнопки выбора внешности, игрока телепортирует на спавн, но виртуальный мир почему-то не изменяется. Вот теперь сам вопрос: нужно ли прописывать в функционал кнопки выбора внешности следующее: "SetPlayerVirtualWorld(playerid, 0);" или же можно сделать как-то по-другому?
2. У меня есть диалоговое окно (например, главного меню (/mm)), в котором есть много всякой всячины, это не так важно. При входе в один из пунктов (например, "команды сервера"), показывается список команд (как на РП серверах список появляется: "основные команды", "управление автомобилем", "управление домом" и т.п.) и нужно сделать так, чтобы при нажатии на клавишу Esc список доступных команд не пропадал полностью, а чтобы возвращало в главное меню. (/mm, заходим в пункт "Команды сервера", нажимаем Esc и возвращаемся в главное меню снова).
3. Третий вопрос насчёт таймера при авторизации и диалогового окна авторизации/регистрации. Нужно как-то сделать таймер при авторизации (например, 60 секунд), чтобы по истечению времени игрока, который не успел авторизоваться, кикало с сервера с текстом "Время на авторизацию истекло.", при этом чтобы закрылось диалоговое окно авторизации. Есть ли где-нибудь мануал на эту тему? Теперь насчёт диалогового окна: как сделать так, чтобы при отказе от регистрации или авторизации (при нажатии на клавишу Esc), игрока кикало с текстом "Вы были кикнуты за отказ от регистрации/авторизации"?
Заранее благодарен за помощь:victory:

Prolific
02.04.2016, 21:28
1) Когда вызывается функция спавна в ТД, туда и пихай SetPlayerVirtualWorld(playerid, 0);
2) if(!response) return Твое меню
3) SetTimerEx в помощь, а так же if(!response)

PawnoNoob
03.04.2016, 19:57
Ещё один вопросик: для команд и для некоторых стоков я использую функцию format, почти везде добавляю переменную new string[128];, при этом использую немного меньше символов, чем выделено. Скажется ли это как-то на работе мода при высоком онлайне, например?
(Пример: выделил 128 символов, а использую 80-100)

DeimoS
03.04.2016, 20:00
Ещё один вопросик: для команд и для некоторых стоков я использую функцию format, почти везде добавляю переменную new string[128];, при этом использую немного меньше символов, чем выделено. Скажется ли это как-то на работе мода при высоком онлайне, например?
(Пример: выделил 128 символов, а использую 80-100)

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

PawnoNoob
03.04.2016, 20:23
Да, скажется. Переполнением стэка, например, и кучей всевозможных багов и крашей из-за этого. Выделяй ровно столько ячеек, сколько требуется

А можете объяснить мне, новичку, что такое "переполнение стэка"? Я лишь учусь пока программированию, поэтому многого не знаю и задаю вот такие глупые вопросы здесь:mosking:

DeimoS
03.04.2016, 20:48
А можете объяснить мне, новичку, что такое "переполнение стэка"? Я лишь учусь пока программированию, поэтому многого не знаю и задаю вот такие глупые вопросы здесь:mosking:

Ну вот максимально упрощённое объяснение, в котором упущенны некоторые моменты:
Стэк - это сегмент данных, который представляет из себя что-то вроде оперативной памяти сервера и хранит в себе данные о работе того коллбэка, который обрабатывается сервером в определённый момент времени. Объявляя локальную переменную (массив), ты "откусываешь" тем самым кусочек от стэка, выделяя этот кусок под хранение данных из переменной (точнее, имя переменной является лишь ключом, по которому ты можешь записать данные в определённый участок стэка и потом этот участок найти, дабы данные извлечь/изменить). Так же в стэк помещается вся информация о вызываемых функциях внутри коллбэка, который обрабатывается в данный момент (выделяется память под имя функции, каждый из аргументов и результат, который возвращает данная функция). А так как стэк - штука не бесконечная (стандартно под него выделяется 16384 байт, чего вполне достаточно, если писать код логически верно), ему свойственно заканчиваться. И если он закончится, а данные для записи всё ещё будут поступать, серверу ничего не останется сделать, как начать перезаписывать уже записанные данные, из-за чего могут начаться серьёзные проблемы и всё выльется в баги.
Вряд ли ты и половину из того, что я написал, понял на 100%... Работа с памятью - тема сложная для понимания в самом начале. Просто послушай совета и выделяй под массивы ровно столько, сколько требуется, а со временем уже поймёшь зачем нужно делать именно так.

PawnoNoob
03.04.2016, 21:34
Ну вот максимально упрощённое объяснение, в котором упущенны некоторые моменты:
Стэк - это сегмент данных, который представляет из себя что-то вроде оперативной памяти сервера и хранит в себе данные о работе того коллбэка, который обрабатывается сервером в определённый момент времени. Объявляя локальную переменную (массив), ты "откусываешь" тем самым кусочек от стэка, выделяя этот кусок под хранение данных из переменной (точнее, имя переменной является лишь ключом, по которому ты можешь записать данные в определённый участок стэка и потом этот участок найти, дабы данные извлечь/изменить). Так же в стэк помещается вся информация о вызываемых функциях внутри коллбэка, который обрабатывается в данный момент (выделяется память под имя функции, каждый из аргументов и результат, который возвращает данная функция). А так как стэк - штука не бесконечная (стандартно под него выделяется 16384 байт, чего вполне достаточно, если писать код логически верно), ему свойственно заканчиваться. И если он закончится, а данные для записи всё ещё будут поступать, серверу ничего не останется сделать, как начать перезаписывать уже записанные данные, из-за чего могут начаться серьёзные проблемы и всё выльется в баги.
Вряд ли ты и половину из того, что я написал, понял на 100%... Работа с памятью - тема сложная для понимания в самом начале. Просто послушай совета и выделяй под массивы ровно столько, сколько требуется, а со временем уже поймёшь зачем нужно делать именно так.

Хм, а вот случайно #pragma dynamic не из-за переполнения стэка приписывается? (просто где-то встречал это: 16.000 байт и прагму) Или я ошибаюсь?
И ещё несколько вопросов сразу появились: можно ли как-нибудь узнать, сколько памяти осталось под эти стэки? Под string выделять ровно столько же символов, сколько занимает строка или же можно "с запасом"? (например: используется 97, выделю 100)

DeimoS
03.04.2016, 22:21
Хм, а вот случайно #pragma dynamic не из-за переполнения стэка приписывается? (просто где-то встречал это: 16.000 байт и прагму) Или я ошибаюсь?
И ещё вопрос сразу появился: можно ли как-нибудь узнать, сколько памяти осталось под эти стэки?

#pragma dynamic позволяет регулировать ту память, которая будет выделяться под стэк. Этой директивой можно как увеличить память, так и уменьшить.
Можно. Зайди в папку с Pawno и создай там файл "pawn.cfg", а после в этом файле напиши "-d3" и сохрани. Теперь компилируй мод и должно появится что-то типа такого:

Pawn compiler 3.2.3664 Copyright (c) 1997-2006, ITB CompuPhase

Header size: 5528 bytes
Code size: 209492 bytes
Data size: 1002600 bytes
Stack/heap size: 16384 bytes; estimated max. usage=698 cells (2792 bytes)
Total requirements: 1234004 bytes
Кол-во выделенной/занимаемой памяти в стэке можно увидеть вот в этой строке:

Stack/heap size: 16384 bytes; estimated max. usage=698 cells (2792 bytes)
Вот указана выделенная (доступная) память:

Stack/heap size: 16384 bytes;
А вот тут показано сколько памяти потребляется на данный момент:

estimated max. usage=698 cells (2792 bytes)
В моём случае это 698 ячеек или, если переводить в байты, 2792 байта из 16384 доступных.
Если значение потребляемой памяти больше значения выделенной - это и есть переполнение. Так же может написать вместо значения потребляемой - "unknown". Это означает, что в моде есть рекурсия, из-за которой компилятор не может определить кол-во потребляемой памяти

PawnoNoob
03.04.2016, 22:27
#pragma dynamic позволяет регулировать ту память, которая будет выделяться под стэк. Этой директивой можно как увеличить память, так и уменьшить.
Можно. Зайди в папку с Pawno и создай там файл "pawn.cfg", а после в этом файле напиши "-d3" и сохрани. Теперь компилируй мод и должно появится что-то типа такого:

Pawn compiler 3.2.3664 Copyright (c) 1997-2006, ITB CompuPhase

Header size: 5528 bytes
Code size: 209492 bytes
Data size: 1002600 bytes
Stack/heap size: 16384 bytes; estimated max. usage=698 cells (2792 bytes)
Total requirements: 1234004 bytes
Кол-во выделенной/занимаемой памяти в стэке можно увидеть вот в этой строке:

Stack/heap size: 16384 bytes; estimated max. usage=698 cells (2792 bytes)
Вот указана выделенная (доступная) память:

Stack/heap size: 16384 bytes;
А вот тут показано сколько памяти потребляется на данный момент:

estimated max. usage=698 cells (2792 bytes)
В моём случае это 698 ячеек или, если переводить в байты, 2792 байта из 16384 доступных.
Если значение потребляемой памяти больше значения выделенной - это и есть переполнение. Так же может написать вместо значения потребляемой - "unknown". Это означает, что в моде есть рекурсия, из-за которой компилятор не может определить кол-во потребляемой памяти

Вот у меня на данный момент есть 13 стеков, каждый выполняет свою функцию, но, как мне кажется, я выделил слишком много символов для формата, поэтому при компилировании я вижу следующее:


Pawn compiler 3.2.3664 Copyright (c) 1997-2006, ITB CompuPhase

Header size: 4344 bytes
Code size: 63952 bytes
Data size: 374036 bytes
Stack/heap size: 16384 bytes; estimated max. usage=491 cells (1964 bytes)
Total requirements: 458716 bytes

И ещё раз повторю свой вопрос, который я добавил немного позднее: под string выделять ровно столько же символов, сколько занимает строка или же можно "с запасом"? (например: используется 97, выделю 100). Считать символы можно, например, на сайте text.ru, при этом добавлять 24? (макс. длина никнейма) (это не реклама, просто сайт для подсчёта символов и проверку текста на уникальность).

DeimoS
03.04.2016, 22:41
Про подсчёт можно почитать тут (http://pro-pawn.ru/showthread.php?13388-%D0%9F%D0%BE%D0%B4%D1%81%D1%87%D1%91%D1%82-%D1%80%D0%B0%D0%B7%D0%BC%D0%B5%D1%80%D0%B0-%D1%84%D0%BE%D1%80%D0%BC%D0%B0%D1%82%D0%B8%D1%80%D1%83%D0%B5%D0%BC%D0%BE%D0%B9-%D1%81%D1%82%D1%80%D0%BE%D0%BA%D0%B8).
А стеков не может быть 13. Ты не так понял, видимо :) Стэк один. Это локальная память.
Если ты говоришь про 13 массивов, то да, это многовато для 13 массивов

PawnoNoob
03.04.2016, 22:52
Про подсчёт можно почитать тут (http://pro-pawn.ru/showthread.php?13388-%D0%9F%D0%BE%D0%B4%D1%81%D1%87%D1%91%D1%82-%D1%80%D0%B0%D0%B7%D0%BC%D0%B5%D1%80%D0%B0-%D1%84%D0%BE%D1%80%D0%BC%D0%B0%D1%82%D0%B8%D1%80%D1%83%D0%B5%D0%BC%D0%BE%D0%B9-%D1%81%D1%82%D1%80%D0%BE%D0%BA%D0%B8).
А стеков не может быть 13. Ты не так понял, видимо :) Стэк один. Это локальная память.
Если ты говоришь про 13 массивов, то да, это многовато для 13 массивов

Ну, видимо, да, не так понял :blum3: 13 stock'ов, несколько форвардов и две команды, которые используют формат (сток, стэк, не знаю, как правильно), ну а так вот нормальны ли показатели при компилировании, которые я написал выше?

DeimoS
03.04.2016, 23:25
Ну, видимо, да, не так понял :blum3: 13 stock'ов, несколько форвардов и две команды, которые используют формат (сток, стэк, не знаю, как правильно), ну а так вот нормальны ли показатели при компилировании, которые я написал выше?

Сток - это оператор и пишется он так - "stock"
Стэк - это сегмент данных и пишется он так "stack"

Нужно смотреть сам код. Ну если действительно так мало массивов создано, то не особо нормально

PawnoNoob
03.04.2016, 23:30
Сток - это оператор и пишется он так - "stock"
Стэк - это сегмент данных и пишется он так "stack"

Нужно смотреть сам код. Ну если действительно так мало массивов создано, то не особо нормально

Последний вопрос, который я хотел бы задать: вот у меня есть система чата, как на RP сервере, под него я выделил 128 символов. В самом же чате я могу написать очень-очень много символов до такой степени, что они дойдут до HUD (до денег или иконки оружия), при этом заходя за границу экрана. Как это можно поправить? Установить какое-нибудь ограничение? Через "if(strlen(inputtext)"? Или это только для диалоговых окон?

Prolific
04.04.2016, 00:13
Да, скажется. Переполнением стэка, например, и кучей всевозможных багов и крашей из-за этого. Выделяй ровно столько ячеек, сколько требуется

Ой ну не приувеличивай. РЛС с этим не заморачивался и работал. Так сказал как буд-то планета с орбиты сойдет из-за этого.

- - - Добавлено - - -


Последний вопрос, который я хотел бы задать: вот у меня есть система чата, как на RP сервере, под него я выделил 128 символов. В самом же чате я могу написать очень-очень много символов до такой степени, что они дойдут до HUD (до денег или иконки оружия), при этом заходя за границу экрана. Как это можно поправить? Установить какое-нибудь ограничение? Через "if(strlen(inputtext)"? Или это только для диалоговых окон?

https://wiki.sa-mp.com/wiki/SendClientMessage
const message[] The text that will be displayed (max 144 characters).

PawnoNoob
04.04.2016, 00:15
Ой ну не приувеличивай. РЛС с этим не заморачивался и работал. Так сказал как буд-то планета с орбиты сойдет из-за этого.

- - - Добавлено - - -



https://wiki.sa-mp.com/wiki/SendClientMessage
const message[] The text that will be displayed (max 144 characters).

А как можно поставить ограничение на количество символов в чате? Чтобы не выходило за границы монитора.

Prolific
04.04.2016, 00:19
А как можно поставить ограничение на количество символов в чате? Чтобы не выходило за границы монитора.

Насколько я знаю оно и не доходит до конца монитора, хотя наверное при разных разрешениях экрана по разному.
Используй strlen,

if(strlen(inputtext) > 144)
strdel(inputtext, 144, strlen(inputtext));

PawnoNoob
04.04.2016, 00:34
Хм-м-м, ну, я даже и не знаю, что здесь можно сказать:blush:
Скриншот:
http://i.imgur.com/22mJ9zu.png
Кусочек кода из OnPlayerText:


new string[128];
format(string, sizeof(string), "%s[%d]: %s", text, получение никнейма, playerid);
SendClientMessage(playerid, 20.0, цвет, string);

Prolific
04.04.2016, 00:37
(playerid, 20.0, цвет, string);
Не много ли параметров?
Показывай перехват SendClientMessage.

PawnoNoob
04.04.2016, 00:39
(playerid, 20.0, цвет, string);
Не много ли параметров?
Показывай перехват SendClientMessage.

Упс, там не SendClientMessage, а вызывается сток, который отвечает за сообщение на расстоянии (ProxDetector) :pleasantry: Это просто я только что сам написал, а не скопировал из своего кода.

DeimoS
04.04.2016, 10:45
Ой ну не приувеличивай. РЛС с этим не заморачивался и работал. Так сказал как буд-то планета с орбиты сойдет из-за этого.

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

#pragma dynamic 80
main()
{
new string[100];
format(string, sizeof(string), "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd");
print(string);
print("Ура, я сработал!");
}
Есть два исхода ситуации для обработки этого кода: с Jit-плагина и без Jit-плагина. Но начать я бы хотел с краткого объяснения того, как работает стэк.

А понять надо именно то, что в стэк данные записываются не обычным образом: от начала к концу (1, 2, 3, 4, 5...), а каждый новый элемент попадает в начало (...5, 4, 3, 2, 1). Проще всего стэк представить как стопку тарелок. Ты не можешь взять тарелку из середины стопки, и засунуть тарелку в середину тоже не можешь. Ты можешь работать только с вершиной стопки. Так же и в стэке. Ему просто не нужно структурировать себя иначе, ибо вся информация попадает в него непрерывным потоком и выдаётся она так же непрерывным потоком (напомню, что стэк, по сути своей, похож на оперативную память, в которую данные загрузились, обработались и тут же выгрузились).
Ну а теперь вернёмся к исходам.


Исход №1: (сразу предупреждаю, с Jit-компиляцией я знаком поверхностно и всё, что я напишу ниже - лишь мои предположения того, почему ошибок о переполнении стэка не появляется)
Особенность Jit-плагина в том, что он не работает с скомпилированным кодом напрямую, а, фактически, компилирует его прямо на ходу. Из-за этого получается так, что все инструкции для работы серверной машины формируются прямо на месте обработки кода => и инструкции по заносу данных в стэк так же формируются на ходу => из-за этого данные, в случае переполнения, просто перезапишут друг друга и если это не приведёт к каким-то серьёзным последствиям (не перезапишется какая-то важная информация или же переполнение будет очень уж большим) - код обработается, но результатом работы будет порча данных.

В нашем случае, если выделить больше ~ 85 ячеек под стэк - оба сообщения отобразятся нормально, а пострадает лишь информация о вызываемых функциях (при обработке в стэк сначала запишется информация о массиве, после запишется информация о вызове format, а после уже информация о print. Но вспомним про стопкообразную структуру стэка и тут следует понять, что информация print просто займёт место о данных о format... Дальше, возможно, будет понятнее :) )
Если же выделить меньше 85 ячеек, "буфера" из информации о вызываемых функциям (а это имя самой функции + информация о параметрах) уже не хватит и строка из print с сообщением "Ура, я сработал!" начнёт "заезжать" на строку из массива, которую мы отобразили ранее и которая в стеке будет находится сразу за строкой "Ура, я сработал!". Следовательно, нуль-символ строки "Ура, я сработал!" будет перезаписан на один из других символов и строки будут отображены вместе, ибо ближайший нуль-символ будет только в массиве. И чем меньше вы выделите памяти под стэк, тем больше строка "Ура, я сработал!" начнёт "съедать" той информации, что была записана ранее. И в консоль начнут отображаться различные лишние символы. Так будет до тех пор, пока вы не уменьшите стэк до тех пор, когда даже для строки "Ура, я сработал!" не хватит места. Тогда даже с Jit -плагином случится ошибка, которая сообщит о переполнении стэка


Исход №2:
Без Jit-плагина даже переполнение на 1 ячейку вызовет ошибку у сервера при обработке кода и весь последующий код (в нашем случае это строка "Ура, я сработал!"), что находился в коллбэке/функции после злополучной строки с переполнением, обработан не будет. А теперь представь, что у тебя таких переполнений несколько по всему моду и они находятся в разных коллбэках/функциях и вызываются разными условиями. И тут, когда у тебя на сервере большой онлайн и, соответственно, частота вызова разных участков кода возрастает, вероятность вызова "больного" кода так же возрастает и начинаются различные проблемы, когда у тебя то одна система начинает работать не правильно (стэк переполнился и код перестал обрабатываться => каким-то переменным не присвоились нужные значения, какие-то функции не вызвались и т.п.), то другая. И ты не можешь понять что происходит, ведь, вроде бы, код весь нормально построен и все условия срабатывают...


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

PawnoNoob
04.04.2016, 17:55
Там было сравнительно небольшое переполнение стэка, которое компенсировалось тем, что коллбэк, отжирающий такое большое кол-во стэка, не выполнялся весь сразу, а в нём выполнялись лишь определённые условия и то самое переполнение стэка просто не успевало происходить. Вот тебе простой пример настоящего переполнения стэка.

#pragma dynamic 80
main()
{
new string[100];
format(string, sizeof(string), "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd");
print(string);
print("Ура, я сработал!");
}
Есть два исхода ситуации для обработки этого кода: с Jit-плагина и без Jit-плагина. Но начать я бы хотел с краткого объяснения того, как работает стэк.

А понять надо именно то, что в стэк данные записываются не обычным образом: от начала к концу (1, 2, 3, 4, 5...), а каждый новый элемент попадает в начало (...5, 4, 3, 2, 1). Проще всего стэк представить как стопку тарелок. Ты не можешь взять тарелку из середины стопки, и засунуть тарелку в середину тоже не можешь. Ты можешь работать только с вершиной стопки. Так же и в стэке. Ему просто не нужно структурировать себя иначе, ибо вся информация попадает в него непрерывным потоком и выдаётся она так же непрерывным потоком (напомню, что стэк, по сути своей, похож на оперативную память, в которую данные загрузились, обработались и тут же выгрузились).
Ну а теперь вернёмся к исходам.


Исход №1: (сразу предупреждаю, с Jit-компиляцией я знаком поверхностно и всё, что я напишу ниже - лишь мои предположения того, почему ошибок о переполнении стэка не появляется)
Особенность Jit-плагина в том, что он не работает с скомпилированным кодом напрямую, а, фактически, компилирует его прямо на ходу. Из-за этого получается так, что все инструкции для работы серверной машины формируются прямо на месте обработки кода => и инструкции по заносу данных в стэк так же формируются на ходу => из-за этого данные, в случае переполнения, просто перезапишут друг друга и если это не приведёт к каким-то серьёзным последствиям (не перезапишется какая-то важная информация или же переполнение будет очень уж большим) - код обработается, но результатом работы будет порча данных.

В нашем случае, если выделить больше ~ 85 ячеек под стэк - оба сообщения отобразятся нормально, а пострадает лишь информация о вызываемых функциях (при обработке в стэк сначала запишется информация о массиве, после запишется информация о вызове format, а после уже информация о print. Но вспомним про стопкообразную структуру стэка и тут следует понять, что информация print просто займёт место о данных о format... Дальше, возможно, будет понятнее :) )
Если же выделить меньше 85 ячеек, "буфера" из информации о вызываемых функциям (а это имя самой функции + информация о параметрах) уже не хватит и строка из print с сообщением "Ура, я сработал!" начнёт "заезжать" на строку из массива, которую мы отобразили ранее и которая в стеке будет находится сразу за строкой "Ура, я сработал!". Следовательно, нуль-символ строки "Ура, я сработал!" будет перезаписан на один из других символов и строки будут отображены вместе, ибо ближайший нуль-символ будет только в массиве. И чем меньше вы выделите памяти под стэк, тем больше строка "Ура, я сработал!" начнёт "съедать" той информации, что была записана ранее. И в консоль начнут отображаться различные лишние символы. Так будет до тех пор, пока вы не уменьшите стэк до тех пор, когда даже для строки "Ура, я сработал!" не хватит места. Тогда даже с Jit -плагином случится ошибка, которая сообщит о переполнении стэка


Исход №2:
Без Jit-плагина даже переполнение на 1 ячейку вызовет ошибку у сервера при обработке кода и весь последующий код (в нашем случае это строка "Ура, я сработал!"), что находился в коллбэке/функции после злополучной строки с переполнением, обработан не будет. А теперь представь, что у тебя таких переполнений несколько по всему моду и они находятся в разных коллбэках/функциях и вызываются разными условиями. И тут, когда у тебя на сервере большой онлайн и, соответственно, частота вызова разных участков кода возрастает, вероятность вызова "больного" кода так же возрастает и начинаются различные проблемы, когда у тебя то одна система начинает работать не правильно (стэк переполнился и код перестал обрабатываться => каким-то переменным не присвоились нужные значения, какие-то функции не вызвались и т.п.), то другая. И ты не можешь понять что происходит, ведь, вроде бы, код весь нормально построен и все условия срабатывают...


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

Очень хорошо написано, но я не думаю, что новичкам, в том числе и мне, это сразу всё будет понятно. Как я понял, под string для формата нужно выделять столько ячеек, сколько требуется для самого вывода текста в чат, например, верно?
Для примера (возможно, я не так понял): команда /kick с выводом текста в чат с помощью format:

new string[103];
format(string, sizeof(string), "Администратор %s кикнул игрока %s. Причина: %s", получаем ник администратора, получаем ник кикнутого игрока, выводим причину.);
SendClientMessageToAll(цвет, string);
Для получения и вывода никнеймов используется 48 символов (24+24), верно? Для причины кика используется 15 символов. Всего с учётом текста и никнеймов с причиной используется максимум 103 символа. Можно ли выделить, например, 105? Или же ровно 103 и ничуть не больше?

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

stock ProxDetector(playerid, Float:range, col, string[])
{
new Float:pos[3], Float:rad;
GetPlayerPos(playerid, pos[0], pos[1], pos[2]);
foreach(Player, i)
{
if(IsPlayerConnected(i) && GetPlayerVirtualWorld(playerid) == GetPlayerVirtualWorld(i))
{
radius = GetPlayerDistanceFromPoint(i, pos[0], pos[1], pos[2]);
if(radius < range/16) SendClientMessage(i, col, string);
else if(rad < range/8) SendClientMessage(i, col, string);
else if(rad < range/4) SendClientMessage(i, col, string);
else if(rad < range/2) SendClientMessage(i, col, string);
else if(rad < range) SendClientMessage(i, col, string);
}
}
return 1;
}
И выводится это в чат с помощью OnPlayerText, что логично:
(из моего мода)

new string[128];
format(string, sizeof(string), "%s[%d]: %s", text, получение никнейма, playerid);
ProxDetector(playerid, 20.0, цвет, string);
Что вот можно сделать, чтобы чат работал нормально и чтобы не было этих выходов за границы монитора?

Profyan
04.04.2016, 18:14
Зачем тебе выделять больше памяти? Наша задача наоборот минимизировать затраты,чтобы повысить производительность.

Про ProxDetector:Есть и другие варианты,более простые. Если разобраться,то тут ничего тяжелого нет. И в этой самописной функции использован стандартный вывод сообщения игроку (SendClientMessage).А через него нельзя вывести,как уже выше упомянули,больше 144 символов.

PawnoNoob
04.04.2016, 18:29
Зачем тебе выделять больше памяти? Наша задача наоборот минимизировать затраты,чтобы повысить производительность.

Про ProxDetector:Есть и другие варианты,более простые. Если разобраться,то тут ничего тяжелого нет. И в этой самописной функции использован стандартный вывод сообщения игроку (SendClientMessage).А через него нельзя вывести,как уже выше упомянули,больше 144 символов.

Про выделение я просто спросил, так как терзали (да и до сих пор терзают) сомнения насчёт этого. И где найти эти "лёгкие" варианты? :smile:

Profyan
04.04.2016, 20:13
Хороший вариант (http://pro-pawn.ru/showthread.php?11482-ProxDetector&p=57134&viewfull=1#post57134)

ziggi
04.04.2016, 21:14
Оригинальная функция ProxDetector выводит сообщения игрокам поблизости, причём цвет сообщений меняется в зависимости от расстояния между игроками. Вы почему-то убрали эту особенность из своих функций, вот правильная:

stock ProxDetector(playerid, Float:max_range, color, string[])
{
new
Float:pos_x,
Float:pos_y,
Float:pos_z,
world,
Float:range,
alpha;

GetPlayerPos(playerid, pos_x, pos_y, pos_z);
world = GetPlayerVirtualWorld(playerid);

foreach (new i : Player) {
if (!IsPlayerStreamedIn(playerid, i) || world != GetPlayerVirtualWorld(i)) {
continue;
}

range = GetPlayerDistanceFromPoint(i, pos_x, pos_y, pos_z);
alpha = floatround((max_range - range) / max_range * 255.0);

SendClientMessage(i, color & (0xFFFFFF00 | alpha), string);
}

return 1;
}

PawnoNoob
04.04.2016, 21:41
Оригинальная функция ProxDetector выводит сообщения игрокам поблизости, причём цвет сообщений меняется в зависимости от расстояния между игроками. Вы почему-то убрали эту особенность из своих функций, вот правильная:

stock ProxDetector(playerid, Float:max_range, color, string[])
{
new
Float:pos_x,
Float:pos_y,
Float:pos_z,
world,
Float:range,
alpha;

GetPlayerPos(playerid, pos_x, pos_y, pos_z);
world = GetPlayerVirtualWorld(playerid);

foreach (new i : Player) {
if (!IsPlayerStreamedIn(playerid, i) || world != GetPlayerVirtualWorld(i)) {
continue;
}

range = GetPlayerDistanceFromPoint(i, pos_x, pos_y, pos_z);
alpha = floatround((max_range - range) / max_range * 255.0));

SendClientMessage(i, color & (0xFFFFFF00 | alpha), string);
}

return 1;
}

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

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

Очень хорошо написано, но я не думаю, что новичкам, в том числе и мне, это сразу всё будет понятно. Как я понял, под string для формата нужно выделять столько ячеек, сколько требуется для самого вывода текста в чат, например, верно?
Для примера (возможно, я не так понял): команда /kick с выводом текста в чат с помощью format:

new string[103];
format(string, sizeof(string), "Администратор %s кикнул игрока %s. Причина: %s", получаем ник администратора, получаем ник кикнутого игрока, выводим причину.);
SendClientMessageToAll(цвет, string);
Для получения и вывода никнеймов используется 48 символов (24+24), верно? Для причины кика используется 15 символов. Всего с учётом текста и никнеймов с причиной используется максимум 103 символа. Можно ли выделить, например, 105? Или же ровно 103 и ничуть не больше?

И ещё один вопрос появился: для инклуда foreach обязательно нужна YSI библиотека?

L0ndl3m
05.04.2016, 15:30
И ещё один вопрос появился: для инклуда foreach обязательно нужна YSI библиотека?
Нет.

PawnoNoob
05.04.2016, 22:23
Спасибо всем за ответы, но на два последних вопроса (если первый так можно назвать) я ещё не получил ответ и очень надеюсь на то, что Вы мне поможете с ответом. Заранее благодарен:read:

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

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


Очень хорошо написано, но я не думаю, что новичкам, в том числе и мне, это сразу всё будет понятно. Как я понял, под string для формата нужно выделять столько ячеек, сколько требуется для самого вывода текста в чат, например, верно?
Для примера (возможно, я не так понял): команда /kick с выводом текста в чат с помощью format:


new string[103];
format(string, sizeof(string), "Администратор %s кикнул игрока %s. Причина: %s", получаем ник администратора, получаем ник кикнутого игрока, выводим причину.);
SendClientMessageToAll(цвет, string);
Для получения и вывода никнеймов используется 48 символов (24+24), верно? Для причины кика используется 15 символов. Всего с учётом текста и никнеймов с причиной используется максимум 103 символа. Можно ли выделить, например, 105? Или же ровно 103 и ничуть не больше?

PawnoNoob
06.04.2016, 21:00
Появился ещё один вопрос по format: я создал переменную new string[200]. В диалоговом окне регистрации у меня, например, 200 букв, пробелов, запятых, цифр, точек и т.д., но при этом есть табуляция (/t, /n) и коды цветов ({FFFFFF} и т.д.), с которыми получается примерно 250 символов. Учитываются ли они (цвета, знаки препинания, цифры, табуляция и т.д.) или же format опускает их при подсчёте символов в строке?

DeimoS
06.04.2016, 21:55
Очень хорошо написано, но я не думаю, что новичкам, в том числе и мне, это сразу всё будет понятно.
Ну так работа с памятью - вообще один из самых сложных аспектов программирования. И в Pawn это ещё очень сильно урезано (язык как раз и создавался для того, чтоб облегчить жизнь новичкам при работе с памятью). Я сам ещё не все аспекты знаю (правильнее сказать, многого не знаю)


Как я понял, под string для формата нужно выделять столько ячеек, сколько требуется для самого вывода текста в чат, например, верно?

Верно. Про нуль-символ, обозначающий конец строки, не забывай

Для получения и вывода никнеймов используется 48 символов (24+24), верно
Совершенно неверно, ибо в таких случаях нужно использовать макросы, которые предоставляют сами разработчики (в случае с никами - MAX_PLAYER_NAME). Представь, что в следующей версии клиента длину ника увеличат. И все твои массивы придётся вручную пересчитывать. Хотя можно было составить вот такую формулу, которая будет просчитана ещё на этапе компиляции и моду серверу не даст:

new string[40+MAX_PLAYER_NAME*2+15+1];
//40 - кол-во символов в строке "Администратор %s кикнул игрока %s. Причина: %s" без спецификаторов (%s, %d, %f и т.п.), которые считать не нужно, ибо в финальной версии сообщения они заменятся на те данные, что ты выводишь.
//MAX_PLAYER_NAME*2 - выделяем место под два ника
//15 - место под причину
//1 - место под нуль символ
и можешь забыть и этом массиве навсегда.


Можно ли выделить, например, 105? Или же ровно 103 и ничуть не больше?
А зачем выделять больше, чем нужно? Ну можешь платить за хлеб не 15 рублей, а 1500. Хуже от этого продавцу не станет, а вот у тебя будут тратится ресурсы впустую. Так же и в нашем случае


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

stock ProxDetector(playerid, Float:range, col, string[])
{
new Float:pos[3], Float:rad;
GetPlayerPos(playerid, pos[0], pos[1], pos[2]);
foreach(Player, i)
{
if(IsPlayerConnected(i) && GetPlayerVirtualWorld(playerid) == GetPlayerVirtualWorld(i))
{
radius = GetPlayerDistanceFromPoint(i, pos[0], pos[1], pos[2]);
if(radius < range/16) SendClientMessage(i, col, string);
else if(rad < range/8) SendClientMessage(i, col, string);
else if(rad < range/4) SendClientMessage(i, col, string);
else if(rad < range/2) SendClientMessage(i, col, string);
else if(rad < range) SendClientMessage(i, col, string);
}
}
return 1;
}
Какая-то странная функция... Зачем оставлена проверка на увеличение расстояния, если цвет везде один? Да и проверка на подключение игрока в foreach... В общем, вот

stock ProxDetector(playerid, Float:range, color, string[])
{
new Float:pos_x,
Float:pos_y,
Float:pos_z,
virtualworld = GetPlayerVirtualWorld(playerid);
GetPlayerPos(playerid, pos_x, pos_y, pos_z);
foreach(Player, i)
{
if(virtualworld != GetPlayerVirtualWorld(i)) continue;
else if(!IsPlayerInRangeOfPoint(i, range, pos_x, pos_y, pos_z)) continue;
else SendClientMessage(i, color, string);
}
return 1;
}


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

- - - Добавлено - - -


Появился ещё один вопрос по format: я создал переменную new string[200]. В диалоговом окне регистрации у меня, например, 200 букв, пробелов, запятых, цифр, точек и т.д., но при этом есть табуляция (/t, /n) и коды цветов ({FFFFFF} и т.д.), с которыми получается примерно 250 символов. Учитываются ли они (цвета, знаки препинания, цифры, табуляция и т.д.) или же format опускает их при подсчёте символов в строке?

Спецсимволы, типа "\t" и "\n" занимают 1 ячейку. Проверить можно так:

new string[10] = "\t\n";
printf("%d", strlen(string));
Код цвета занимает 8 символов

PawnoNoob
06.04.2016, 22:07
Ух ты, теперь-то я всё понял, кроме нескольких мелочей:
- под нуль-символ нужно выделять один символ в переменной?
- что означает функция (или как это называется) continue?

else if(!IsPlayerInRangeOfPoint(i, range, pos_x, pos_y, pos_z)) continue;
- в format учитывается всё, кроме табуляции, которая занимает 1 символ вместо двух, всё верно? Остальное (цвета и т.д.) по одному символу (цвет 8, буква, цифра по одному). А вот если у меня, допустим, есть дефайн, например "imyaservera" (P.S. Английский знаю хорошо, выдумал на ходу :D), в котором написано имя сервера (чтобы быстро изменять, мало ли), и в диалоге регистрации/авторизации написано следующее "велком ту "imyaservera"...", как здесь высчитывать количество символов для переменной? Учитывать ли кавычки?

VVWVV
06.04.2016, 22:16
1. Под нуль символ также нужно выделять место, ибо данные будут склеены.
2. Это оператор, он пропускает (прерывает) итерацию.
3. Да. Ассемблерный листинг:


; {888888}Some\0
dump 7b 46 46 46 46 46 46 7d 53 6f 6d 65 0 ; Знака \n нет

; {888888}\nSome\0
dump 7b 46 46 46 46 46 46 7d a 53 6f 6d 65 0 ; Есть.

PawnoNoob
06.04.2016, 22:19
1. Под нуль символ также нужно выделять место, ибо данные будут склеены.
2. Это оператор, он пропускает (прерывает) итерацию.
3. Да. Ассемблерный листинг:


; {888888}Some\0
dump 7b 46 46 46 46 46 46 7d 53 6f 6d 65 0 ; Знака \n нет

; {888888}\nSome\0
dump 7b 46 46 46 46 46 46 7d a 53 6f 6d 65 0 ; Есть.


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

VVWVV
06.04.2016, 22:25
Ох, как-то сложно Вы объяснили, так как я ещё не совсем понимаю значения этих слов из программирования... Сколько места нужо выделить для нуль-символа? И что такое "Ассемблерный листинг"? О_О И что такое "итерация"?

Для нуль-символа требуется всего лишь одна ячейка, как и для других символов.
Итерация (https://ru.wikipedia.org/wiki/%D0%98%D1%82%D0%B5%D1%80%D0%B0%D1%86%D0%B8%D1%8F)


А вот если у меня, допустим, есть дефайн, например "imyaservera" (P.S. Английский знаю хорошо, выдумал на ходу :D), в котором написано имя сервера (чтобы быстро изменять, мало ли), и в диалоге регистрации/авторизации написано следующее "велком ту "imyaservera"...", как здесь высчитывать количество символов для переменной? Учитывать ли кавычки?


#define SERVER "Some Name"

static const name[] = "Welcome to "SERVER;
const SIZE = sizeof name;

DeimoS
06.04.2016, 22:28
Ух ты, теперь-то я всё понял, кроме нескольких мелочей:
- под нуль-символ нужно выделять один символ в переменной?
- что означает функция (или как это называется) continue?

else if(!IsPlayerInRangeOfPoint(i, range, pos_x, pos_y, pos_z)) continue;
- в format учитывается всё, кроме табуляции, которая занимает 1 символ вместо двух, всё верно? Остальное (цвета и т.д.) по одному символу (цвет 8, буква, цифра по одному). А вот если у меня, допустим, есть дефайн, например "imyaservera" (P.S. Английский знаю хорошо, выдумал на ходу :D), в котором написано имя сервера (чтобы быстро изменять, мало ли), и в диалоге регистрации/авторизации написано следующее "велком ту "imyaservera"...", как здесь высчитывать количество символов для переменной? Учитывать ли кавычки?

1) Да. Нуль-символ указывается таким же спец-символом, как и \n, только "\0" и так же занимает 1 символ.
2) Это, как сказали выше, оператор, пропускающий текущую итерацию. Итерация - это одно повторение кода в цикле. Например, вот тут

for(new i = 1; i <= 10; i++)
Будет 10 итераций. Можешь загуглить, если до сих пор не понятно
3) Содержимое макросов заменяется в момент компиляции, так что нужно высчитывать не длину имени макроса, а именно длину содержимого этого макроса.
А учитывать нужно и то, что заполнители, типа "%s", "%d", "%02d" и т.п. - не занимают места вообще. Но если ты их будешь учитывать, то это пока не так критично. Лучше подожди момента, когда сможешь осознать почему ты делаешь именно так, а не иначе, ибо иначе ты создашь больше проблем для себя, чем пользы.

PawnoNoob
06.04.2016, 23:36
Всё-таки в голову пришёл ещё один вопрос. Не сам по себе, конечно, но всё же задам Вам: наткнулся на функцию обновления аккаунта (ну, снятие затычки, выход из тюрьмы и т.д.) и там присутствует цикл:

for(new i; i < MAX_PLAYERS; i++)
Заранее прочитал о нём в интернете и сделал вывод, что он не такой уж и хороший, гораздо лучше использовать foreach.

foreach(Player, i)
Так вот, сами вопросы:
- действительно ли foreach лучше первого цикла?
- нужен ли вообще этот цикл в обновлении аккаунта?
- какая разница между этими двумя циклами?
- и что вообще означает i и i++? (MAX_PLAYERS хоть знаю :diablo:)

Profyan
07.04.2016, 05:12
1.Да,быстрее.
2.Если у тебя сохранение общее, то да.А если хочешь только определенного игрока сохранить - то нет.В функцию передавай параметр id игрока.
3.В скорости. for.. - является частью языка.foreach - сторонняя разработка.foreach ориентирован на определенное множество.Подробнее можете почитать на официальном форуме или воспользоваться поиском на этом форуме.
4.i - переменная-счетчик.С каждой итерацией цикла она изменяется. i++ - задаем шаг(увеличиваем на единицу после каждой итерации). i++ - постинкремент.

DeimoS
07.04.2016, 08:29
- какая разница между этими двумя циклами?

Цикл for, как уже сказали - стандартный цикл. foreach же представляет из себя самописанную систему, которая содержит в себе массив и ряд циклов, срабатывающих при подключении/выходе игрока на сервер.
Представим, что на сервере такая картина: нулевой и первый слот - заняты, второй и третий - свободны, четвёртый - занят, пятый - свободен, шестой - занят.
Стандартный цикл в любом случае начнёт свою проверку с нулевой ячейки и закончит 999-ой (в MAX_PLAYERS в 0.3.7 хранится число 1000). Хоть даже и на сервере всего 4 игрока. В SA-MP 0.3.7 так же добавили функцию, которая возвращает последний занятый ID на сервере, но тогда цикл, опять же, сделает 7 итераций (с 0 по 6), а не 4.
А foreach же реализована система, которая запишет ID игроков по порядку в один массив и выглядеть массив "изнутри" будет так:

0 ячейка - ID 0
1 ячейка - ID 1
2 ячейка - ID 4
3 ячейка - ID 6
И уже цикл, для которого, для удобства, придуман макрос "foreach", будет обращаться не к ID игрока, а к ячейкам массива и извлекать ID игрока из ячеек массива, прогоняя тем самым только те ID, что подключены к серверу.
Если на сервер подключится новый игрок, в foreach, благодаря ряду условий внутри цикла в OnPlayerConnect, новый ID (в нашем случае первый свободный ID - 2) запишется не в конец цикла (после 6), а именно на своё законное место - после двух, "сдвинув" все остальные ID на ячейку. Так же и при отключении - ячейка не станет свободной, а foreach просто возьмёт и сдвинет все последующее ID, шедшие после отключившегося от сервера, на одну ячейку назад. Благодаря этим новым действиям, которые совершаются с подключённым игроком, foreach и работает быстрее (если не понял, то foreach прогоняет в себе лишь те ID, которые подключены к серверу и никакие другие. Поэтому и проверка на то, подключён ли ID, вызываемый циклом (IsPlayerConnected) просто не нужна - он точно подключён).
Так же в foreach имеется возможность создавать свои итераторы. Но это уже отдельная большая темаю


- и что вообще означает i и i++? (MAX_PLAYERS хоть знаю :diablo:)
"i" - Это обычная переменная, которая нужна циклу для того, чтоб подсчитывать число повторений (итераций), совершённых при работе с циклом. Ты можешь обозвать эту переменную как угодно, просто в программировании принято переменные цикла обзывать именно таким, сокращённым видом (дабы ты понимал, "i" исходит от "iterator").
"i++" - это обычное математическое действие, которое идентично записи "i = i+1" или же "i += 1". То есть, тут ты просто прибавляешь к переменной единицу. Можешь просто загуглить

PawnoNoob
07.04.2016, 10:09
Цикл for, как уже сказали - стандартный цикл. foreach же представляет из себя самописанную систему, которая содержит в себе массив и ряд циклов, срабатывающих при подключении/выходе игрока на сервер.
Представим, что на сервере такая картина: нулевой и первый слот - заняты, второй и третий - свободны, четвёртый - занят, пятый - свободен, шестой - занят.
Стандартный цикл в любом случае начнёт свою проверку с нулевой ячейки и закончит 999-ой (в MAX_PLAYERS в 0.3.7 хранится число 1000). Хоть даже и на сервере всего 4 игрока. В SA-MP 0.3.7 так же добавили функцию, которая возвращает последний занятый ID на сервере, но тогда цикл, опять же, сделает 7 итераций (с 0 по 6), а не 4.
А foreach же реализована система, которая запишет ID игроков по порядку в один массив и выглядеть массив "изнутри" будет так:

0 ячейка - ID 0
1 ячейка - ID 1
2 ячейка - ID 4
3 ячейка - ID 6
И уже цикл, для которого, для удобства, придуман макрос "foreach", будет обращаться не к ID игрока, а к ячейкам массива и извлекать ID игрока из ячеек массива, прогоняя тем самым только те ID, что подключены к серверу.
Если на сервер подключится новый игрок, в foreach, благодаря ряду условий внутри цикла в OnPlayerConnect, новый ID (в нашем случае первый свободный ID - 2) запишется не в конец цикла (после 6), а именно на своё законное место - после двух, "сдвинув" все остальные ID на ячейку. Так же и при отключении - ячейка не станет свободной, а foreach просто возьмёт и сдвинет все последующее ID, шедшие после отключившегося от сервера, на одну ячейку назад. Благодаря этим новым действиям, которые совершаются с подключённым игроком, foreach и работает быстрее (если не понял, то foreach прогоняет в себе лишь те ID, которые подключены к серверу и никакие другие. Поэтому и проверка на то, подключён ли ID, вызываемый циклом (IsPlayerConnected) просто не нужна - он точно подключён).
Так же в foreach имеется возможность создавать свои итераторы. Но это уже отдельная большая темаю


"i" - Это обычная переменная, которая нужна циклу для того, чтоб подсчитывать число повторений (итераций), совершённых при работе с циклом. Ты можешь обозвать эту переменную как угодно, просто в программировании принято переменные цикла обзывать именно таким, сокращённым видом (дабы ты понимал, "i" исходит от "iterator").
"i++" - это обычное математическое действие, которое идентично записи "i = i+1" или же "i += 1". То есть, тут ты просто прибавляешь к переменной единицу. Можешь просто загуглить

Но всё же, что лучше использовать для обновления (не сохранения) аккаунта? Стандартный for или самописный foreach?

Nash_Brigers
07.04.2016, 10:23
Но всё же, что лучше использовать для обновления (не сохранения) аккаунта? Стандартный for или самописный foreach?Вам же расписали их отличия.. Конечно foreach..

PawnoNoob
07.04.2016, 15:17
Ну вот, допустим я создал этот сток для обновления аккаунта:


stock uacc()
{
foreach(Player, i)
{
if(pinfo[i][mut] > 0)
{
pinfo[i][mut]--;
if(pinfo[i][mut] <= 0)
{
pinfo[i][mut] = 0;
SendClientMessage(playerid, цвет, "бана чата больше нет.");
}
}
}
}
p.s. в моём коде всё чики-пуки, для примера написал без копирования из кода (нет таких mut, pinfo и т.д., но это никого не волнует, ну мало ли скажете "фу ну и код"):blush2:
1. Всё ли нормально в самом стэке? Могут ли наблюдаться проблемы в будущем?
2. Так как я изучаю программирование на конкретных примерах (используя другие моды, находящиеся в открытом доступе, ну и задавая совсем глупые вопросы Вам) и я, ради интереса, решил "заценить" систему обновления аккаунтов в разных модах:
- В одном моде после слов "stock uacc ()" в скобочках пишется "playerid" и нету циклов (foreach, i; i<MAX_PLAYERS и т.д.)
- В другом моде после слов "stock uacc ()" в скобочках ничего не пишется, но при этом используется цикл (new i; i < MAX_PLAYERS; i++).
Сам вопрос: что вообще нужно писать в скобочках, если используется foreach?
3. Нужно ли использовать функцию (или как это правильно назвать) "continue;" после SendClientMessage для пропуска итерации?

TheMallard
07.04.2016, 15:22
1. Со стэком все будет в порядке, если будете экономными, в данном коде ему даже ничего не грозит.
2. foreach(new i : Player)

P.S. Рекомендую к прочтению - http://pro-pawn.ru/showthread.php?8347

PawnoNoob
07.04.2016, 18:55
В общем, решил сделать таймер обновления аккаунта, но не тут-то было. Как я уже говорил, я изучаю программирование на конкретных примерах, но иногда я сталкиваюсь с такими моментами, где мне почти ничего не знакомо и я не знаю, за что отвечает та или иная функция. Так вот, вернёмся к самому таймеру. В одном из модов мне удалось найти более-менее адекватный таймер с высчитыванием времени, но я не знаю, что за что отвечает:


public Timer_Unix()
{
if(timers_unix > -1)
{
unix = gettime(tmphour, tmpminute, tmpsecond);

if(unix_hour <= unix)
{
Hour();
unix_hour = unix+3600;
}
else if(unix_min <= unix)
{
Minutes();
unix_min = unix+60;
}
else if(unix_sec <= unix)
{
Second();
unix_sec = unix+1;
}
}
return 1;
}
И переменные:


new timers_unix = -1;
new unix, unix_hour, unix_min, unix_sec;
new tmphour, tmpminute, tmpsecond;

Я предполагаю, что gettime - получение времени компьютера (или сервера), unix_hour(_min, _sec) - час, минута, секунда.
Посмотрев по коду ещё можно узнать, что hour - это система зарплаты, которая выдаётся раз в час, minutes - обновление складов, вывод сообщения раз в n-минут, а second - обновление аккаунта (которое, кстати, я сейчас и пытаюсь сделать).
А что дают остальные функции? Ну, unix+1 - раз в секунду, а остальное что означает?

Nexius_Tailer
07.04.2016, 20:07
В общем, решил сделать таймер обновления аккаунта, но не тут-то было. Как я уже говорил, я изучаю программирование на конкретных примерах, но иногда я сталкиваюсь с такими моментами, где мне почти ничего не знакомо и я не знаю, за что отвечает та или иная функция. Так вот, вернёмся к самому таймеру. В одном из модов мне удалось найти более-менее адекватный таймер с высчитыванием времени, но я не знаю, что за что отвечает:


public Timer_Unix()
{
if(timers_unix > -1)
{
unix = gettime(tmphour, tmpminute, tmpsecond);

if(unix_hour <= unix)
{
Hour();
unix_hour = unix+3600;
}
else if(unix_min <= unix)
{
Minutes();
unix_min = unix+60;
}
else if(unix_sec <= unix)
{
Second();
unix_sec = unix+1;
}
}
return 1;
}
И переменные:


new timers_unix = -1;
new unix, unix_hour, unix_min, unix_sec;
new tmphour, tmpminute, tmpsecond;

Я предполагаю, что gettime - получение времени компьютера (или сервера), unix_hour(_min, _sec) - час, минута, секунда.
Посмотрев по коду ещё можно узнать, что hour - это система зарплаты, которая выдаётся раз в час, minutes - обновление складов, вывод сообщения раз в n-минут, а second - обновление аккаунта (которое, кстати, я сейчас и пытаюсь сделать).
А что дают остальные функции? Ну, unix+1 - раз в секунду, а остальное что означает?
Придумано довольно умно. Таймер, предполагаю, вызывается каждую секунду.

Собственно, объясню по частям:


new timers_unix = -1;
new unix, unix_hour, unix_min, unix_sec;
new tmphour, tmpminute, tmpsecond;

Тут объявляются переменные для таймера. timers_unix будет, судя по коду дальше, хранить ид таймера. unix_(hour/min/sec) нужны для постоянного хранения прошедшего времени. Под прошедшим временем понимается unix time (это число секунд, прошедших с 1 января 1970 года если не ошибаюсь). Переменные tmp(hour/minute/second) как-бы (по идее автора наверное) нужны только для заполнения аргументов для функции "gettime", которая вызывается в таймере, но по сути они не нужны, ибо для узнавания только unix-time'а можно просто вызвать "gettime" без параметров вообще.


public Timer_Unix()
{
if(timers_unix > -1) //
{
Здесь какая-то нужная проверка, скорее всего при запуске таймера "Timer_Unix" переменной "timers_unix" присваивается ид этого таймера. А т.к. эта переменная по умолчанию -1, то код не будет выполняться, если таймер не запущен (т.е. если public Timer_Unix() был вызван не таймером). В общем дальше.


unix = gettime(tmphour, tmpminute, tmpsecond);
Тут мы записываем этот unix-time в переменную unix, чтобы далее...


if(unix_hour <= unix)
{
Hour();
unix_hour = unix+3600;
}
сверять её с переменными, которым, если условие выполнится (а первый раз оно в любом случае выполнится), будет присвоено значение текущего количества секунд + час в эквиваленте секунд (а 1 час это как раз и есть 3600 секунд)


else if(unix_min <= unix)
{
Minutes();
unix_min = unix+60;
}
Либо минута в эквиваленте секунд (а это как раз 60)


else if(unix_sec <= unix)
{
Second();
unix_sec = unix+1;
}
Либо просто плюс одна секунда.

Делается это для того, чтобы не заводить отдельные таймеры на одну секунду, одну минуту и один час, а просто в секундном таймере узнавать "новый" unix-time, сверять его с прошедшими часами (в эквиваленте секунд), и если час прошёл, т.е. значение текущего unix-time'а достигло значения того, который мы поставили ("unix_hour = unix+3600;"), значит вызываем события, которые должны быть раз в один час (подразумевая, что эти события есть "Hour()"). Аналогично с минутами и с секундами.

Может не так и понятно объяснил, но надеюсь, дойдёт)

PawnoNoob
07.04.2016, 21:53
А что такое "DeAMX"? Как эту функцию использовать и нужна ли она вообще?

Desulaid
07.04.2016, 21:57
А что такое "DeAMX"? Как эту функцию использовать и нужна ли она вообще?

Когда есть это (http://pro-pawn.ru/showthread.php?8277), меня ничего не интересует другое :)

PawnoNoob
07.04.2016, 22:03
Когда есть это (http://pro-pawn.ru/showthread.php?8277), меня ничего не интересует другое :)

А-а-а, значит эта штуковина мне не очень-то и нужна. Почему? Потому что я ещё учусь программированию и "пишу" (:D) мод не для открытия сервера, а просто так, для обучения и для интереса. Глянуть, что да как.

Всё же осталось несколько вопросов касательно кода:
Вопрос номер один:
Ну вот, допустим я создал этот сток для обновления аккаунта (не такой некрасивый, а грамотный, всё красиво оформлено, нет никаких mut, uacc и т.д.):


stock uacc()
{
foreach(Player, i)
{
if(pinfo[i][mut] > 0)
{
pinfo[i][mut]--;
if(pinfo[i][mut] <= 0)
{
pinfo[i][mut] = 0;
SendClientMessage(playerid, цвет, "бана чата больше нет.");
}
}
}
}
Нужно ли использовать функцию (или как это правильно назвать) "continue;" после SendClientMessage для пропуска итерации?
Вопрос номер два: (цитирую)
Так как я изучаю программирование на конкретных примерах (используя другие моды, находящиеся в открытом доступе, ну и задавая совсем глупые вопросы Вам) и я, ради интереса, решил "заценить" систему обновления аккаунтов в разных модах:
- В одном моде после слов "stock uacc ()" в скобочках пишется "playerid" и нету циклов (foreach, i; i<MAX_PLAYERS и т.д.)
- В другом моде после слов "stock uacc ()" в скобочках ничего не пишется, но при этом используется цикл (new i; i < MAX_PLAYERS; i++).
Сам вопрос: что вообще нужно писать в скобочках, если используется foreach?

Daniel_Cortez
07.04.2016, 22:16
Нужно ли использовать функцию (или как это правильно назвать) "continue;" после SendClientMessage для пропуска итерации?

Это называется оператором.
Вообще, я бы не советовал вам заострять внимание на расстановке continue, т.к., ИМХО, она относится к низкоуровневым оптимизациям, для правильного применения которых нужно разбираться в том, какой код генерируется в .amx из вашего исходного кода на Pawn.

PawnoNoob
07.04.2016, 23:07
Решил "прогнать" ещё раз систему регистрации, вводя максимальные значения для данных:
Адрес электронной почты - 34 символа.
Пароль - 14 символов.
Если ввести в диалоговом окне для ввода адреса электронной почты 32 символа, то в базе данных аккаунт сохранится с почтой "1", а если ввести 33 и более символа, то аккаунт вообще не сохранится.

Использую плагин regex с дефайном из официальной темы:


#define IsValidEmail(%1) \
regex_match(%1, "[a-zA-Z0-9_\\.]+@([a-zA-Z0-9\\-]+\\.)+[a-zA-Z]{2,4}")
Код из моего мода:


case 5:
{
if(!IsValidEmail(inputtext))
{
SendClientMessage(playerid, цвет, "введён неверный адрес электронной почты.");
// здесь вызывается stock диалогового окна ввода адреса электронной почты.
}
else
{
// здесь код создания аккаунта с вводом адреса электронной почты.
}
}
Для длины запроса выделено 149 (MAX_PLAYER_NAME+91+34) символов, а сам запрос выглядит так:

INSERT INTO `accounts` (`ник`, `пароль`, `адрес электронной почты `) VALUES ('%s', '%s', '%s') // выдуманные, не настоящие названия столбцов.
И кстати, если ввести 32 и менее символов, то аккаунт зарегистрируется с введённым адресом электронной почты и при этом нормально сохранится.

И, конечно же, строчка из лога MySQL (совсем забыл про неё :) ):

(error #1064) You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''здесь ввведённый адрес эл. почты' at line 1

vovandolg
08.04.2016, 05:55
Адрес электронной почты - 34 символа.

жмяк жмяк (http://pro-pawn.ru/showthread.php?10548-%D0%A1%D0%BE%D0%B7%D0%B4%D0%B0%D0%BD%D0%B8%D0%B5-%D1%81%D0%B8%D1%81%D1%82%D0%B5%D0%BC%D1%8B-%D1%80%D0%B5%D0%B3%D0%B8%D1%81%D1%82%D1%80%D0%B0%D1%86%D0%B8%D0%B8-%D0%BD%D0%B0-%D0%BE%D1%81%D0%BD%D0%BE%D0%B2%D0%B5-%D0%BF%D0%BB%D0%B0%D0%B3%D0%B8%D0%BD%D0%B0-MySQL-R39-2&p=71137&viewfull=1#post71137)

PawnoNoob
08.04.2016, 16:44
жмяк жмяк (http://pro-pawn.ru/showthread.php?10548-%D0%A1%D0%BE%D0%B7%D0%B4%D0%B0%D0%BD%D0%B8%D0%B5-%D1%81%D0%B8%D1%81%D1%82%D0%B5%D0%BC%D1%8B-%D1%80%D0%B5%D0%B3%D0%B8%D1%81%D1%82%D1%80%D0%B0%D1%86%D0%B8%D0%B8-%D0%BD%D0%B0-%D0%BE%D1%81%D0%BD%D0%BE%D0%B2%D0%B5-%D0%BF%D0%BB%D0%B0%D0%B3%D0%B8%D0%BD%D0%B0-MySQL-R39-2&p=71137&viewfull=1#post71137)

Хм, а сколько нужно выделять символов под адрес электронной почты? Не думаю, что у кого-то будет адрес электронной почты длиной в 129 символов, а тем более в 320. :to_take_umbrage:

[ForD]
08.04.2016, 16:54
жмяк жмяк (http://pro-pawn.ru/showthread.php?10548-%D0%A1%D0%BE%D0%B7%D0%B4%D0%B0%D0%BD%D0%B8%D0%B5-%D1%81%D0%B8%D1%81%D1%82%D0%B5%D0%BC%D1%8B-%D1%80%D0%B5%D0%B3%D0%B8%D1%81%D1%82%D1%80%D0%B0%D1%86%D0%B8%D0%B8-%D0%BD%D0%B0-%D0%BE%D1%81%D0%BD%D0%BE%D0%B2%D0%B5-%D0%BF%D0%BB%D0%B0%D0%B3%D0%B8%D0%BD%D0%B0-MySQL-R39-2&p=71137&viewfull=1#post71137)
+

Вот только недавно был вопрос-же Клик (http://pro-pawn.ru/showthread.php?13729)

PawnoNoob
08.04.2016, 17:09
;72341']+

Вот только недавно был вопрос-же Клик (http://pro-pawn.ru/showthread.php?13729)

Так дело в том, что я прочитал всё, что написано про максимальный размер адреса электронной почты и формулу, которую "вывел" continue (http://pro-pawn.ru/member.php?3392-continue), но какой человек подумает сделать себе адрес электронной почты размером в 320 символов? :wacko: Система регистрации у меня сделана полностью, но всё же при вводе 33 символов и более аккаунт просто-напросто не сохраняется, хотя выделено 34, но в остальных случаях (при вводе меньшего количества символов адреса электронной почты) всё работает верно.
Если что, код расписан здесь (http://pro-pawn.ru/showthread.php?13713-%D0%9D%D0%B5%D1%81%D0%BA%D0%BE%D0%BB%D1%8C%D0%BA%D0%BE-%D0%B2%D0%BE%D0%BF%D1%80%D0%BE%D1%81%D0%BE%D0%B2&p=72311&viewfull=1#post72311).

[ForD]
08.04.2016, 17:40
Так дело в том, что я прочитал всё, что написано про максимальный размер адреса электронной почты и формулу, которую "вывел" continue (http://pro-pawn.ru/member.php?3392-continue), но какой человек подумает сделать себе адрес электронной почты размером в 320 символов? :wacko: Система регистрации у меня сделана полностью, но всё же при вводе 33 символов и более аккаунт просто-напросто не сохраняется, хотя выделено 34, но в остальных случаях (при вводе меньшего количества символов адреса электронной почты) всё работает верно.
Если что, код расписан здесь (http://pro-pawn.ru/showthread.php?13713-%D0%9D%D0%B5%D1%81%D0%BA%D0%BE%D0%BB%D1%8C%D0%BA%D0%BE-%D0%B2%D0%BE%D0%BF%D1%80%D0%BE%D1%81%D0%BE%D0%B2&p=72311&viewfull=1#post72311).

Поверь,все может быть) ну это про размер.
А на счет остального пока лень писать,уже датый)

PawnoNoob
08.04.2016, 17:59
;72346']Поверь,все может быть) ну это про размер.
А на счет остального пока лень писать,уже датый)

:sarcastic: ну, бывает) Подожду ответа другого пользователя, если кто-то вообще захочет помочь:to_take_umbrage:

Seregamil
08.04.2016, 18:58
:sarcastic: ну, бывает) Подожду ответа другого пользователя, если кто-то вообще захочет помочь:to_take_umbrage:


if( strlen( inputtext ) > нужное_количество ) {
return ...
}?

PawnoNoob
08.04.2016, 19:26
if( strlen( inputtext ) > нужное_количество ) {
return ...
}?


if(!IsValidEmail(inputtext) || if(strlen(inputtext)) < 6 || if(strlen(inputtext)) > 33)
{
SendClientMessage(playerid, цвет, "некорректный емаил");
// показ диалога ввода.
}
Вот так?

PawnoNoob
08.04.2016, 23:51
Я очень невнимателен, потому что в начале строки с ошибкой указывается паблик, из-за которого "крашит" регистрацию (или как это правильно назвать), так вот, вот здесь (http://pro-pawn.ru/showthread.php?13713-%D0%9D%D0%B5%D1%81%D0%BA%D0%BE%D0%BB%D1%8C%D0%BA%D0%BE-%D0%B2%D0%BE%D0%BF%D1%80%D0%BE%D1%81%D0%BE%D0%B2&p=72311&viewfull=1#post72311) полностью описана моя проблема. И эта проблема возникает из-за паблика "uploadplayeraccountnumber", который я взял из урока (http://pro-pawn.ru/showthread.php?10548-%D0%A1%D0%BE%D0%B7%D0%B4%D0%B0%D0%BD%D0%B8%D0%B5-%D1%81%D0%B8%D1%81%D1%82%D0%B5%D0%BC%D1%8B-%D1%80%D0%B5%D0%B3%D0%B8%D1%81%D1%82%D1%80%D0%B0%D1%86%D0%B8%D0%B8-%D0%BD%D0%B0-%D0%BE%D1%81%D0%BD%D0%BE%D0%B2%D0%B5-%D0%BF%D0%BB%D0%B0%D0%B3%D0%B8%D0%BD%D0%B0-MySQL-R39-2) от пользователя Deimos (http://pro-pawn.ru/member.php?2548-DeimoS). Не знаю, что делать в этой ситуации и очень надеюсь на Вашу помощь. Заранее очень благодарен.

DeimoS
09.04.2016, 13:09
Я очень невнимателен, потому что в начале строки с ошибкой указывается паблик, из-за которого "крашит" регистрацию (или как это правильно назвать), так вот, вот здесь (http://pro-pawn.ru/showthread.php?13713-%D0%9D%D0%B5%D1%81%D0%BA%D0%BE%D0%BB%D1%8C%D0%BA%D0%BE-%D0%B2%D0%BE%D0%BF%D1%80%D0%BE%D1%81%D0%BE%D0%B2&p=72311&viewfull=1#post72311) полностью описана моя проблема. И эта проблема возникает из-за паблика "uploadplayeraccountnumber", который я взял из урока (http://pro-pawn.ru/showthread.php?10548-%D0%A1%D0%BE%D0%B7%D0%B4%D0%B0%D0%BD%D0%B8%D0%B5-%D1%81%D0%B8%D1%81%D1%82%D0%B5%D0%BC%D1%8B-%D1%80%D0%B5%D0%B3%D0%B8%D1%81%D1%82%D1%80%D0%B0%D1%86%D0%B8%D0%B8-%D0%BD%D0%B0-%D0%BE%D1%81%D0%BD%D0%BE%D0%B2%D0%B5-%D0%BF%D0%BB%D0%B0%D0%B3%D0%B8%D0%BD%D0%B0-MySQL-R39-2) от пользователя Deimos (http://pro-pawn.ru/member.php?2548-DeimoS). Не знаю, что делать в этой ситуации и очень надеюсь на Вашу помощь. Заранее очень благодарен.

Полностью код uploadplayeraccountnumber покажи

$continue$
09.04.2016, 15:51
Я что ли составляю стандарты RFC (https://ru.wikipedia.org/wiki/RFC)?
А это как раз стандарт - RFC 0821 (http://www.studfiles.ru/preview/322141/)

Так дело в том, что я прочитал всё, что написано про максимальный размер адреса электронной почты и формулу, которую "вывел" continue (http://pro-pawn.ru/member.php?3392-continue)
Например, я сделаю почту в 320 символов. У вас будет стоять, например 128 символов (без проверки на strlen, что делать максимально глупо), ввожу я значит > 128 символов, Вы ловите краш запроса и выход за пределы массива?
Стрельба в ногу, дело добровольное. И вообще, Вы знаете что ник 24 символа, при этом 24 это не константа в плане < или >. То есть я могу зарегистрировать ник и в 10 символов, выделяйте тогда 10 ячеек?
Вот вам банальный пример где бы пригодился оператор "new (https://ru.wikipedia.org/wiki/New_%28C%2B%2B%29)"

но какой человек подумает сделать себе адрес электронной почты размером в 320 символов? :wacko:

L0ndl3m
09.04.2016, 15:59
Вот вам банальный пример где бы пригодился оператор "new (https://ru.wikipedia.org/wiki/New_%28C%2B%2B%29)"
У new в pawn другое предназначение.

$continue$
09.04.2016, 16:01
Хмм, а ты уверен, что я имел введу new именно в Pawn?
Я имел введу, что в Pawn не помешала бы динамическая память.

У new в pawn другое предназначение.

Daniel_Cortez
09.04.2016, 16:14
Хмм, а ты уверен, что я имел введу new именно в Pawn?
Я имел введу, что в Pawn не помешала бы динамическая память.
GVar в помощь. Или, если вероисповедание не позволяет использовать чужие плагины, можно воспользоваться SetPVarString. Правда, чем больше внутренний индекс PVar'ов, тем медленнее доступ к ним. Если создать PVar с именем "var_a", у него будет индекс 0, а если вслед за ним объявить "var_b", ему будет присвоен индекс 1 (для тех, кто в танке: индекс зависит от порядка создания, а не от названия). При доступе к PVar'ам сервер производит линейный поиск по всей таблице PVar'ов - следовательно, самый быстрый доступ будет к тому PVar'у, который был создан самым первым, а к самому последнему PVar'у будет медленнее всего.

PawnoNoob
09.04.2016, 20:01
Я что ли составляю стандарты RFC (https://ru.wikipedia.org/wiki/RFC)?
А это как раз стандарт - RFC 0821 (http://www.studfiles.ru/preview/322141/)

Например, я сделаю почту в 320 символов. У вас будет стоять, например 128 символов (без проверки на strlen, что делать максимально глупо), ввожу я значит > 128 символов, Вы ловите краш запроса и выход за пределы массива?
Стрельба в ногу, дело добровольное. И вообще, Вы знаете что ник 24 символа, при этом 24 это не константа в плане < или >. То есть я могу зарегистрировать ник и в 10 символов, выделяйте тогда 10 ячеек?
Вот вам банальный пример где бы пригодился оператор "new (https://ru.wikipedia.org/wiki/New_%28C%2B%2B%29)"

Ну смотрите, я сделал проверку на strlen и у меня это выглядит так:

if(!IsValidEmail(inputtext) || strlen(inputtext) < 10 || strlen(inputtext) > 34)
Но если я, например, пропишу в адресе электронной почты 33 или 34 символа, то аккаунт просто-напросто не создастся в базе данных. Если же впишу 32, то всё будет нормально. Я всё перепроверил несколько раз: в базе данных выделено 34 символа для адреса электронной почты, в enum - 34, при загрузке аккаунта также 34, но всё равно возникает эта ошибка из-за форварда UploadPlayerAccountNumber, который я взял из урока пользователя Deimos.

forward UploadPlayerAccountNumber(playerid);
public UploadPlayerAccountNumber(playerid) pInfo[playerid][pID] = cache_insert_id(mysql_connect_id);
(только вместо mysql_connect_id я вставил название моей переменной для подключения)

$continue$
10.04.2016, 02:27
Я, вроде четко изложил свой мысли?
Нет смысла ограничивать игрока в вводе email, ну конечно, если этот email не > 320 символов.

PawnoNoob
10.04.2016, 10:41
Я, вроде четко изложил свой мысли?
Нет смысла ограничивать игрока в вводе email, ну конечно, если этот email не > 320 символов.

Ну а какой смысл давать игрокам возможность ввода такого огромного количества символов для адреса электронной почты, если почти все игроки вводят [email protected] и подобные значения (на серверах, где нет регистрации с подтверждением почты)

$continue$
10.04.2016, 12:41
Какой вообще тогда смысл делать ввод почты?

Ну а какой смысл давать игрокам возможность ввода такого огромного количества символов для адреса электронной почты, если почти все игроки вводят [email protected] и подобные значения (на серверах, где нет регистрации с подтверждением почты)

DeimoS
10.04.2016, 13:43
Какой вообще тогда смысл делать ввод почты?

"Везде есть ввод почты и у меня должен быть"

- - - Добавлено - - -


Ну смотрите, я сделал проверку на strlen и у меня это выглядит так:

if(!IsValidEmail(inputtext) || strlen(inputtext) < 10 || strlen(inputtext) > 34)
Но если я, например, пропишу в адресе электронной почты 33 или 34 символа, то аккаунт просто-напросто не создастся в базе данных. Если же впишу 32, то всё будет нормально. Я всё перепроверил несколько раз: в базе данных выделено 34 символа для адреса электронной почты, в enum - 34, при загрузке аккаунта также 34, но всё равно возникает эта ошибка из-за форварда UploadPlayerAccountNumber, который я взял из урока пользователя Deimos.

forward UploadPlayerAccountNumber(playerid);
public UploadPlayerAccountNumber(playerid) pInfo[playerid][pID] = cache_insert_id(mysql_connect_id);
(только вместо mysql_connect_id я вставил название моей переменной для подключения)

Число ячеек в массиве для хранения запроса увеличь

[ForD]
10.04.2016, 14:14
Ну а какой смысл давать игрокам возможность ввода такого огромного количества символов для адреса электронной почты, если почти все игроки вводят [email protected] и подобные значения (на серверах, где нет регистрации с подтверждением почты)

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

PawnoNoob
10.04.2016, 14:45
;72378']Не! Рили! На кой колос вам тогда почта нужна? В чем прикол? Али типа если есть сохранение почты - сервер куул,али нету-сервер кал?
Дак сделайте просто диалог с полем ввода,и дальше сообщение,вау чел,ты записал свою почту,йо-йо,продолжай в том-же духе,а в итоге откроешь ему следующий диалог,тип твоя почта круто сохранена на нашем куул сервере,нажми "ок" и играй..
Да-да,бомбануло..

Дело в том, что у меня после ввода адреса электронной почты сразу телепортирует на спавн, но, как я уже и говорил, если ввести 33 символа в адресе электронной почты, то аккаунт просто-напросто не запишется в базе данных. Я пробовал менять, ставил 65, 128 ставил и всё равно не сохраняет, если вводишь на 1 символ меньше выделенного.

- - - Добавлено - - -


"Везде есть ввод почты и у меня должен быть"

- - - Добавлено - - -



Число ячеек в массиве для хранения запроса увеличь

Для адреса электронной почты? У меня стоит 34.

Nash_Brigers
10.04.2016, 15:01
;72378']Не! Рили! На кой колос вам тогда почта нужна? В чем прикол?
Какой вообще тогда смысл делать ввод почты?Для восстановления пароля, например.

vovandolg
10.04.2016, 15:28
Контрольный вопрос уж легче замутить, кликуха пса, где родился, во сколько крестился и т.д.:crazy:

[ForD]
10.04.2016, 16:11
Для восстановления пароля, например.


Ну а какой смысл давать игрокам возможность ввода такого огромного количества символов для адреса электронной почты, если почти все игроки вводят [email protected] и подобные значения ---->>>> (на серверах, где нет регистрации с подтверждением почты) <<<<------

Так.. Ну ладно..
Суть была в том,нахера делать почту там,где нет подтверждения? Для красоты? Какое может быть восстановление пароля?..

Nash_Brigers
10.04.2016, 16:35
;72383']Так.. Ну ладно..
Суть была в том,нахера делать почту там,где нет подтверждения? Для красоты? Какое может быть восстановление пароля?..
Ты можешь зарегистрироваться без подтверждения, а в будущем забыть пароль.. К примеру, после 3х неверных вводов тебе предлагает выслать новый (или старый, кому как удобнее) пароль на мыло, указанное при регистрации.


Контрольный вопрос уж легче замутить, кликуха пса, где родился, во сколько крестился и т.д.:crazy:
Какие нах клички собак? Вместо пароля так же можно кличку собаки вписать.. Этому разговору не будет конца "что удобнее", "как проще"..

$continue$
10.04.2016, 16:37
Я смотрю, месье Вы у нас закончили университет по информационной безопасности. А то вон какой безопасный метод предлагаете сделать.

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

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

[ForD]
10.04.2016, 19:05
Ты можешь зарегистрироваться без подтверждения, а в будущем забыть пароль.. К примеру, после 3х неверных вводов тебе предлагает выслать новый (или старый, кому как удобнее) пароль на мыло, указанное при регистрации.


Какие нах клички собак? Вместо пароля так же можно кличку собаки вписать.. Этому разговору не будет конца "что удобнее", "как проще"..

Ну забыл ты пароль,захотел восстановить с помощью мыла,и куда тебе придет код восстановления? На [email protected]? В чем профит делать сохранение невалидной почты?

//-----------


Для адреса электронной почты? У меня стоит 34.


Число ячеек в "массиве для хранения запроса" увеличь

PawnoNoob
10.04.2016, 19:57
;72387']Ну забыл ты пароль,захотел восстановить с помощью мыла,и куда тебе придет код восстановления? На [email protected]? В чем профит делать сохранение невалидной почты?

//-----------

Блин, значит я слишком сильно затупил, когда пересчитывал количество ячеек для запроса и указал слишком мало, теперь всё сохраняется. Спасибо огромное за помощь всем :smile::yahoo:

- - - Добавлено - - -

В одном из сообщений в данной теме мне рассказали, что в fomat некоторые символы занимают одну ячейку (табуляция), а некоторые вообще их не занимают (%s, %d). Так вот: я, высчитывая количество ячеек для запроса, убирал эти спецсимволы из запроса, чтобы получить максимальное количество символов для запроса, а потом уже вставлял сами данные. Мой запрос при создании аккаунта выглядит так:

INSERT INTO `accounts` (`Nickname`, `Password`, `Email`) VALUES ('%s', '%s', '%s')
Он занимает 82 ячейки.
Заполненный запрос (пароль и адрес электронной почты) занимает 126 символов и должен выглядеть примерно так:

new query[127+MAX_PLAYER_NAME];
Но всё равно я, указывая большее количество символов (больше 130 вроде как), не добивался нужного результата, но теперь, указав следующее:

new query[170+MAX_PLAYER_NAME];
всё же добился результата и аккаунты сохраняются в базу данных с максимальным значением пароля, адреса электронной почты и никнейма.

Так вот, что всё-таки учитывается в format? (ну, учитываются ли эти спецсиволы, что сколько значений занимает)

Daniel_Cortez
10.04.2016, 20:46
В одном из сообщений в данной теме мне рассказали, что в fomat некоторые символы занимают одну ячейку (табуляция), а некоторые вообще их не занимают (%s, %d).
Некорректно говорить, что "%s" и "%d" не занимают место, ведь форматная строка и текст, получившийся в результате работы format - совершенно разные строки. В одной форматные спецификаторы есть, а в другой они заменятся на соответствующие им данные.
Вообще в Pawn все символы в строке занимают по 1 ячейке (или по 1 байту в случае с упакованными строками).



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

INSERT INTO `accounts` (`Nickname`, `Password`, `Email`) VALUES ('%s', '%s', '%s')
Он занимает 82 ячейки.
Заполненный запрос (пароль и адрес электронной почты) занимает 126 символов и должен выглядеть примерно так:

new query[127+MAX_PLAYER_NAME];
Но всё равно я, указывая большее количество символов (больше 130 вроде как), не добивался нужного результата, но теперь, указав следующее:

new query[170+MAX_PLAYER_NAME];
всё же добился результата и аккаунты сохраняются в базу данных с максимальным значением пароля, адреса электронной почты и никнейма.

Так вот, что всё-таки учитывается в format? (ну, учитываются ли эти спецсиволы, что сколько значений занимает)
Вам же приводили ссылку ещё на 1-й странице...

DeimoS
10.04.2016, 21:39
Завязывайте с оффтопом. Последующие сообщения, в которых не будет чёткого ответа на заданный вопрос, а будет "сделай лучше так, ведь мне так больше нравится" и прочий бред, будут удаляться, а автор будем карать варн(а позже и бан-)хаммером.

[ForD]
10.04.2016, 21:57
Завязывайте с оффтопом. Последующие сообщения, в которых не будет чёткого ответа на заданный вопрос, а будет "сделай лучше так, ведь мне так больше нравится" и прочий бред, будут удаляться, а автор будем карать варн(а позже и бан-)хаммером.

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

Excel_Smit.
11.04.2016, 07:41
Приветствую! У меня, как у новичка в Pawn, есть несколько вопросов относительно программирования, ответы на которых, к сожалению, я не смог найти в поисковике:
1. После того, как его телепортирует в интерьер, ему "присваивается" виртуальный мир, равный его id (игрок с id 1, значит вирт. мир при выборе внешности равен 1).

SetPlayerVirtualWorld(playerid, playerid + 1);

Ибо игрок с ид 0 возможно встретиться с игроками на основной карте.

PawnoNoob
11.04.2016, 22:45
SetPlayerVirtualWorld(playerid, playerid + 1);

Ибо игрок с ид 0 возможно встретиться с игроками на основной карте.

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

PawnoNoob
11.04.2016, 23:31
Появился ещё один небольшой вопросик относительно mysql_function_query, а именно для его значений:
допустим, у меня есть команда для назначения игрока на пост администратора с внесением его данных в другую таблицу (назовём её "adm").
После ввода значений, а именно id игрока и уровень администратора, данные о статистике администратора заносятся в таблицу "adm" с запросом:

format(QUERY, sizeof(QUERY), "INSERT INTO `adm` (`nick`, `lvl`) VALUES ('%s', '%i')", pi[params[0]][name], params[1]
и выполняется это функцией

mysql_function_query(baza, QUERY, true, "", "");
Так вот, сами вопросы звучат так:
1. Когда нужно использовать true, а когда false?
2. Какие значения помимо этого нужно указывать именно в данном запросе? (назначение на должность администратора не из стока, запрос прямо в команде)
3. Нужно ли указывать "i", playerid" в конце запроса и когда вообще нужно это указывать? (пример из урока Deimos'а ниже)
4. Если много раз прописать команду назначения администратора на одного и того же игрока, то в базу данных добавит столько же строк, сколько раз ввёл команду. Как сделать так, чтобы даже после флуда этой командой (или же повышения/понижения уровня) изменялась одна строка, а не добавлялась новая?
Для примера приведу функцию поиска аккаунта в базе данных из урока Deimos'a:

mysql_function_query(mysql_connect_id, query_string, true, "FindPlayerInTable","i", playerid);

* Не думайте, что у меня настолько фиговый код ("pi", "name", "baza"), у меня всё хорошо написано, это лишь для примера. Не нужно давать мне ссылок на темы типа "правильное оформление кода" }:(

PawnoNoob
13.04.2016, 15:22
Тема упала немножко, и правила раздела не запрещают поднимать её.:sad:

vovandolg
13.04.2016, 18:12
Ты просто не видишь что выше твоей темы есть закрепленные темы, в которых есть тема где задают такие вопросы чтобы не флудили мелочными темами и постами как у тебя :declare:

DeimoS
17.04.2016, 15:02
1. Когда нужно использовать true, а когда false?
Параметр с true/false является лишь синтаксическим сахаром. Если открыть инклюд a_mysql, можно найти вот такой макрос

#define mysql_function_query(%0,%1,%2,%3,"%4"%5) mysql_tquery(%0,%1,%3,#%4%5)
где видно, что 3-ий параметр (%2 - это и есть "true/false)" никак не передаётся в функцию mysql_tquery.
Для чего нужен этот параметр? Просто для того, чтоб тебе самому можно было проще ориентироваться в своём коде. Принято ставить "true" когда в результате запроса будет возвращён какой-то результат, с которым потом нужно будет работать (выгрузка данных из БД в мод), а "false", когда запрос происходит в одностороннем порядке к БД и не возвращает результат (хотя он его возвращает, но это уже другая история)
Так же вполне возможно, что данный параметр просто оставили для совместимости с предыдущими версиями, где он реально что-то означал. Сильно в лог разработки плагина MySQL не вникал, поэтому сказать не могу


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



3. Нужно ли указывать "i", playerid" в конце запроса и когда вообще нужно это указывать? (пример из урока Deimos'а ниже)
Если у функции, которая вызывается в результате запроса, есть аргументы и тебе нужно передать какие-то данные в эти аргументы - да, нужно. В том примере, что ты указал, я передаю в функцию "FindPlayerInTable" целочисленные данные ("i" - integer), которые будут взяты из параметра "playerid"


4. Если много раз прописать команду назначения администратора на одного и того же игрока, то в базу данных добавит столько же строк, сколько раз ввёл команду. Как сделать так, чтобы даже после флуда этой командой (или же повышения/понижения уровня) изменялась одна строка, а не добавлялась новая?
Для примера приведу функцию поиска аккаунта в базе данных из урока Deimos'a:

mysql_function_query(mysql_connect_id, query_string, true, "FindPlayerInTable","i", playerid);

Ну вот так же, как и я, делай. После ввода в команду ID игрока, ищи его на сервере и если есть - составляй запрос на поиск ника игрока в базе данных админов. Если есть - выполняй желаемые действия (либо делай запрос "UPDATE", либо не делай запрос "INSERT", либо просто сообщай, мол игрок уже админ)