PDA

Просмотр полной версии : [CMD] Restart



Desulaid
07.11.2015, 23:30
Команда позволяет перезапустить ваш сервер любым удобным вам вариантом: в определенное время и немедленно! Вы можете установить авто-рестарт на определенный момент времени вплоть до секунд и можете изменить это время. Все данные сохраняются в файл '../scriptfilse/restart.ini'. Если вы забыли на какое время установлен авто-рестарт, то можете это узнать (не открывая файл '../scriptfilse/restart.ini' или можете там :3). Если вам понадобится отменить рестарт, то пожалуйста.

Автор: Untonyst


#include <dc_cmd>
#include <sscanf2>
#include <mxINI>

new
restart_hour, restart_minute, restart_second,
restart_timer;

const DEFAULT_RESTART_HOUR = 00, DEFAULT_RESTART_MINUTE = 00, DEFAULT_RESTART_SECOND = 00;

enum
{
DLG_RESTART_INPUT_OR_NOT = 1,
DLG_RESTART_INPUT_INFO
};

COMMAND:restart(playerid, params[])
{
if(sscanf(params, "i", params[0]))
{
SendClientMessage(playerid, 0xAAC5E3FF, "{FFFFFF}Введите /restart <тип>");
SendClientMessage(playerid, 0xAAC5E3FF, "{FFFACD}Типы{FFFFFF}:");
SendClientMessage(playerid, 0xAAC5E3FF, "{FFFACD}| {FFFFFF}0 {FFFACD}- узнать время на рестарт");
SendClientMessage(playerid, 0xAAC5E3FF, "{FFFACD}| {FFFFFF}1 {FFFACD}- установить новое время");
SendClientMessage(playerid, 0xAAC5E3FF, "{FFFACD}| {FFFFFF}2 {FFFACD}- загрузить последние изменения");
SendClientMessage(playerid, 0xAAC5E3FF, "{FFFACD}| {FFFFFF}3 {FFFACD}- перезапустить сервер сейчас");
SendClientMessage(playerid, 0xAAC5E3FF, "{FFFACD}| {FFFFFF}4 {FFFACD}- отменить рестарт");
return 0;
}
switch(params[0])
{
case 0:
{
static const format_message[] = "{FFFACD}Рестарт произойдет в {FFFFFF}%i:%i:%i {FFFACD}!";
new send_message[sizeof(format_message) + (-6) + 6 + 1];
format(send_message, sizeof(send_message), format_message, restart_hour, restart_minute, restart_second);
SendClientMessage(playerid, 0xAAC5E3FF, send_message);
return 1;
}
case 1:
{
return ShowPlayerDialog(playerid, DLG_RESTART_INPUT_OR_NOT, DIALOG_STYLE_MSGBOX, "Установка времени на рестарт:", "{FFFFFF}Вы действительно хотите обновить время на рестарт сервера?", "Да", "Нет");
}
case 2:
{
if(!fexist("restart.ini"))
{
SendClientMessage(playerid, 0xAAC5E3FF, "{FF6347}Невозможно совершить выбранное действие!");
return 0;
}
new restart_file = ini_openFile("restart.ini");
ini_getInteger(restart_file, "hour", restart_hour);
ini_getInteger(restart_file, "minute", restart_minute);
ini_getInteger(restart_file, "second", restart_second);
ini_closeFile(restart_file);
restart_timer = SetTimer("ServerRestart", 500, false);
SendClientMessage(playerid, 0xAAC5E3FF, "{32CD32}Данные успешно загруженны!");
return 1;
}
case 3:
{
SendClientMessageToAll(0xAAC5E3FF, "{FF6347}Происходит рестарт сервера!");
GameModeExit();
return 1;
}
case 4:
{
SendClientMessageToAll(0xAAC5E3FF, "{FF6347}Рестарт был отменен!");
KillTimer(restart_timer);
return 1;
}
default:
{
SendClientMessageToAll(0xAAC5E3FF, "{FF6347}Указан не верный тип рестарта!");
}
}
return 1;
}

forward ServerRestart();
public ServerRestart()
{
new hour, minute, second;
gettime(hour, minute, second);

if(hour == restart_hour && minute == restart_minute && second == restart_second)
{
SendClientMessageToAll(0xAAC5E3FF, "{FF6347}Происходит рестарт сервера!");
GameModeExit();
return 1;
}
restart_timer = SetTimer("ServerRestart", 500, false);
return 1;
}

public OnDialogResponse(playerid, dialogid, response, listitem, inputtext[])
{

switch(dialogid)
{
case DLG_RESTART_INPUT_OR_NOT:
{
if(!response)
return 0;
ShowPlayerDialog(playerid, DLG_RESTART_INPUT_INFO, DIALOG_STYLE_INPUT, "Установка времени на рестарт:", "{FFFFFF}Введите время на рестарт, разделяя часы, минуты и секунды запятыми!", "Ввести", "Отмена");
}
case DLG_RESTART_INPUT_INFO:
{
if(!response)
return 0;

if(!strlen(inputtext))
return 0;

if(strlen(inputtext) < 3 && strlen(inputtext) > 6)
return 0;

for(new i = strlen(inputtext) - 1; i != -1; i--)
if ((inputtext[i] >= '0' && inputtext[i] <= '9') ||
(inputtext[i] == ',')) continue;
else
return 0;

sscanf(inputtext, "p<,>iii", restart_hour, restart_minute, restart_second);

if(!(0 <= restart_hour <= 23) || !(0 <= restart_minute <= 59) || !(0 <= restart_second <= 59))
return 0;

new restart_file = ini_openFile("restart.ini");
ini_setInteger(restart_file, "hour", restart_hour);
ini_setInteger(restart_file, "minute", restart_minute);
ini_setInteger(restart_file, "second", restart_second);
ini_closeFile(restart_file);

static const format_message[] = "{FFFACD}Время на рестарт обновленно на %i:%i:%i";
new send_message[sizeof(format_message) + (-6) + 6 + 1];
format(send_message, sizeof(send_message), format_message, restart_hour, restart_minute, restart_second);
SendClientMessage(playerid, 0xAAC5E3FF, send_message);
}
}
return 1;
}



Копирование данной темы без разрешения автора запрещено!

$continue$
08.11.2015, 12:43
А, где логика то? Осталась с теми пользователями (с которыми ты общаешься) на ПИ?
В чем кайф проверить подключен ли sscanf? Ну а если он не подключен, то опять использовать функции sscanf...
Да и кстати, isnull есть не только в sscanf, он есть и в MySQL (плагин от BlueG), DC_CMD, etc.




#if !defined sscanf
if(isnull(params))
return SendClientMessage(playerid, -1, "Введите /restart [время(сек.)]");
#else
if(sscanf(params, "i", params[0]))
return SendClientMessage(playerid, -1, "Введите /restart [время(сек.)]");
#endif

Почему нельзя объявить константу? Например:



const MAX_RESTART_TIME = 60;
if(params[0] > MAX_RESTART_TIME)
{
SendClientMessage(playerid, -1, "Вы отложили слишком много времени до рестарта!");
SendClientMessage(playerid, -1, "{FF6347}Максимальное отложенное время - это 60 секунд.");
return 1;
}






if(params[0] > 60)
{
SendClientMessage(playerid, -1, "Вы отложили слишком много времени до рестарта!");
SendClientMessage(playerid, -1, "{FF6347}Максимальное отложенное время - это 60 секунд.");
return 1;
}


Для общей информации:


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

@__FuncName();
@__FuncName() print("Прошла 1 секунда с момента запуска мода");
public OnGameModeInit()
{
SetTimer("@__FuncName", 1000, false);
}




forward @__server_restart(time);
public @__server_restart(time)

Полный фейл. Вернуть везде единицу.
Магическое_число_(программирование) (https://ru.wikipedia.org/wiki/Магическое_число_(программирование))




if((time > 60) || (time <= -2))
return 1;


Ну и так не по теме:

http://i.imgur.com/v51Wm0M.png




static const string[] = "~r~%i";
new format_string[sizeof(string)];
format(format_string, sizeof(format_string), string, time+1);

Desulaid
08.11.2015, 14:47
А, где логика то? Осталась с теми пользователями (с которыми ты общаешься) на ПИ?
В чем кайф проверить подключен ли sscanf? Ну а если он не подключен, то опять использовать функции sscanf...
Да и кстати, isnull есть не только в sscanf, он есть и в MySQL (плагин от BlueG), DC_CMD, etc.

Ты не понял как работаю условия?


#если sscanf НЕ подключен
<используем возможности dc_cmd>
#если подключен
<используем возможности sscanf>
#конец


Ты попробуй скомпилировать команду с sscanf и без него. Все скомпилируется без ошибок.



Почему нельзя объявить константу? Например:



const MAX_RESTART_TIME = 60;
if(params[0] > MAX_RESTART_TIME)
{
SendClientMessage(playerid, -1, "Вы отложили слишком много времени до рестарта!");
SendClientMessage(playerid, -1, "{FF6347}Максимальное отложенное время - это 60 секунд.");
return 1;
}


А смысл в создании константы, которую мы будем использовать один раз -_-.



Для общей информации:

// бла бла бла :D


Если разницы нет, то в чем проблема?



Полный фейл. Вернуть везде единицу.
Магическое_число_(программирование) (https://ru.wikipedia.org/wiki/Магическое_число_(программирование))

Ну даже не знаю, тут, скорее я соглашусь, но это не "полный фейл" ("ду ю спик инглиш ...")
А здесь я просто культурно промолчу ...

Daniel_Cortez
08.11.2015, 22:14
1. Максимальное время рестарта можно вынести в макрос: #define в начале функции и #undef в конце.
Тогда его можно будет использовать и в сообщении:

SendClientMessage(playerid, -1, "Максимальное отложенное время - " #MAX_RESTART_TIME " секунд.");
Btw, для чего нужно было ставить "{FF6347}" в начало сообщение, когда можно было указать этот цвет вместо "-1"?

2. Команда вообще тестировалась без sscanf2?



#if !defined sscanf
if(isnull(params))
return SendClientMessage(playerid, -1, "Введите /restart [время(сек.)]");
#else

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

3. Вот этот отрывок надолго заставил меня задуматься:



forward @__server_restart(time);
public @__server_restart(time)
{

Во-первых, в чём смысл задавать названию префикс "@__", когда она уже имеет атрибут public.
Или наоборот, зачем ставить forward/public, когда уже есть "@__"? Либо одно, либо другое, определись уже.
Во-вторых, что помешало назвать функцию в стиле CamelCase, как другие функции?
В-третьих, вместо аргумента time прще было бы сделать глобальную переменную, разве что задав ей более сложное имя.
Заодно, так будет проще обрабатывать ситуации, когда команда /restart вводилась несколько раз - в этом случае можно сделать вывод сообщение о том, что таймер уже запущен.

4.



static const string[] = "~r~%i";
new format_string[sizeof(string)];

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

Desulaid
08.11.2015, 22:40
Если честно, то я не вижу смысла в этом. Да, это все хорошо, и для дальнейшей разработки идеально просто, но зачем? Планировать рестарт за более минуту - бред же.
В принципе да, сейчас использование sscanf своего рода обязанность.
> убрал условие
Что ж вас так напрягает это место. Ладно, исправлю, но все равно оставлю в under_score.
PS. надеюсь, вас не напрягают функции у pBlueG типа mysql_function_query :dntknw:
Не совсем :)

main()
{
#define EXAMPLE (228)
static const string[] = "~r~%i";
new format_string[sizeof(string)+2];
format(format_string, sizeof(format_string), string, EXAMPLE);
print(format_string); // >.<
}

Desulaid
08.11.2015, 23:46
Вроде, что что вы хотели, учел. Плюс решил добавить обратно вариант без sscanf, ну мало ли :)

Daniel_Cortez
09.11.2015, 08:21
Если честно, то я не вижу смысла в этом. Да, это все хорошо, и для дальнейшей разработки идеально просто, но зачем? Планировать рестарт за более минуту - бред же.

Универсальность. Представь себя администратором на каком-нибудь сервере. В твои обязанности входит делать рестарт сервера каждый день в 0:00 по МСК. Но после трудного дня ты устал и очень хочешь спать. Сейчас 23:30 и ты мог бы поставить таймер рестарта на 30 минут (1800 секунд) - НО ТЫ НЕ МОЖЕШЬ, потому что автор команды посчитал, что никому не пригодится ставить таймер больше, чем на 1 минуту.




Что ж вас так напрягает это место.

Использовать "@" в названии функции, которая уже объявлена, как public - это как масло масляное.
Не то, чтобы я собираюсь пользоваться этим кодом (скажу даже больше, я уже давно не работаю ни над какими серьёзными проектами на Pawn), но мне не всё равно, что постят на Pro-Pawn.




PS. надеюсь, вас не напрягают функции у pBlueG типа mysql_function_query :dntknw:

Исключение только подтверждает наличие правила. Функции MySQL (и SQLite в стандартной поставке сервера) названы в нижнем регистре только потому, что они названы так в оригинальном коде на C/C++.
Само же правило строится на том, в каком стиле названо большинство функций в SA:MP - а они названы в стиле CamelCase. Именно поэтому я выбрал тот стиль в своей статье с рекомендациями.





main()
{
#define EXAMPLE (228)
static const string[] = "~r~%i";
new format_string[sizeof(string)+2];
format(format_string, sizeof(format_string), string, EXAMPLE);
print(format_string); // >.<
}

Назначение названий string и format_string всё ещё перепутано.
Откуда взята формула "sizeof(string)+2"?
И да, макрос EXAMPLE так и продолжит работать за пределами функции.



Вроде, что что вы хотели, учел. Плюс решил добавить обратно вариант без sscanf, ну мало ли :)
Только нагромождение излишним функционалом. Мало того, команда никак не отреагирует, если игрок вместо числа введёт какой-нибудь текст (strval вернёт 0).
Кстати, чуть не забыл, отрицательное число тоже логично было бы считать, как неправильный аргумент (для немедленного рестарта можно ввести 0).

Desulaid
09.11.2015, 16:47
Универсальность. Представь себя администратором на каком-нибудь сервере. В твои обязанности входит делать рестарт сервера каждый день в 0:00 по МСК. Но после трудного дня ты устал и очень хочешь спать. Сейчас 23:30 и ты мог бы поставить таймер рестарта на 30 минут (1800 секунд) - НО ТЫ НЕ МОЖЕШЬ, потому что автор команды посчитал, что никому не пригодится ставить таймер больше, чем на 1 минуту.
Для подобный плановых случаев на сервере должен быть авторестарт. Моя же команда - установка не планового рестарта.

Использовать "@" в названии функции, которая уже объявлена, как public - это как масло масляное.
Не то, чтобы я собираюсь пользоваться этим кодом (скажу даже больше, я уже давно не работаю ни над какими серьёзными проектами на Pawn), но мне не всё равно, что постят на Pro-Pawn.
Лучше напихаю во всем моде кучу констант, которые я буду использовать один раз, ЗАТО ПОНЯТНО ЖЕ ВСЕ!
https://pp.vk.me/c624426/v624426763/625db/hzD3ccBjXcE.jpg

Исключение только подтверждает наличие правила. Функции MySQL (и SQLite в стандартной поставке сервера) названы в нижнем регистре только потому, что они названы так в оригинальном коде на C/C++.

Ладно, твой стандарт есть стандарт, стандарт как никак (правда, который был принят тобой, а ты дискриминировал стандарт вики с CamelCase и стараешься всем приманить under_core в плане названия переменных :sad:). Но все же, это не так уж затруднит понимание код следующим программистом.


Назначение названий string и format_string всё ещё перепутано.
Откуда взята формула "sizeof(string)+2"?
И да, макрос EXAMPLE так и продолжит работать за пределами функции.
Это просто как вариант, того что, добавив две ячейки три цифры пройдут.

Только нагромождение излишним функционалом. Мало того, команда никак не отреагирует, если игрок вместо числа введёт какой-нибудь текст (strval вернёт 0).
Кстати, чуть не забыл, отрицательное число тоже логично было бы считать, как неправильный аргумент (для немедленного рестарта можно ввести 0).
Как никак моментальный рестарт тоже нужен, мало ли что может случиться. Если время на 0, то игрокам оповещение о рестарте все равно придет, так как я указал его появление при -1. А ввод отрицательных чисел надо исправить.

Daniel_Cortez
12.11.2015, 08:12
Для подобный плановых случаев на сервере должен быть авторестарт. Моя же команда - установка не планового рестарта.

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




Лучше напихаю во всем моде кучу констант, которые я буду использовать один раз, ЗАТО ПОНЯТНО ЖЕ ВСЕ!
https://pp.vk.me/c624426/v624426763/625db/hzD3ccBjXcE.jpg

Не совсем пойму, о чём ты. Равно, как и о сути картинки.




Это просто как вариант, того что, добавив две ячейки три цифры пройдут.

Логики в расчёте всё равно не видно. По идее сначала должно быть отнятие длины спецификатора ("%d" - 2 символа), а затем добавление длины форматируемого числа (в данном случае 2-3, но для простоты настройки можно добавить 11, на случай, если максимальное время рестарта будет установлено в cellmax - вряд ли будет что-то плохое от 8 ячеек).




Как никак моментальный рестарт тоже нужен, мало ли что может случиться. Если время на 0, то игрокам оповещение о рестарте все равно придет, так как я указал его появление при -1. А ввод отрицательных чисел надо исправить.

Именно об этом и была речь.




Ладно, твой стандарт есть стандарт, стандарт как никак (правда, который был принят тобой, а ты дискриминировал стандарт вики с CamelCase и стараешься всем приманить under_core в плане названия переменных :sad:).

Ты так говоришь, как будто в этом есть что-то плохое.
Идентификаторы в стиле lowerCamelCase легче перепутать с названиями функций в UpperCamelCase. К тому же, во многих других языках принято записывать в lowerCamelCase именно названия функций, что только усиливает путаницу при освоении этих языков после Pawn.
Поэтому вполне логично использовать стиль snake_case для обозначения переменных, ведь так их сложнее спутать с функциями при беглом просмотре кода. Ну уж всяко лучше, чем заставлять задерживаться (пусть и на очень короткое время) на каждой строке.
Это во-первых.

Во-вторых, в SA:MP wiki нет и никогда не было оговорено никакого единого стандарта. Более того, этот факт уже обсуждался между нами ранее (http://pro-pawn.ru/showthread.php?8347&p=62251&viewfull=1#post62251).

В-третьих, не я придумывал все те правила из стандарта (моей инициативой были только названия переменных - и я уже объяснил почему).
Почти все правила были взяты либо из стиля кодинга в стандартных инклудах SA:MP (константы и "константоподобные" макросы - в ALL_CAPS, функции - в UpperCamelCase, etc.), либо из других популярных стандартов по C/C++.
И да, мне приходится требовать их соблюдения со стороны тех, кто выкладывает здесь работы. В конце концов, если использовать в своём моде сразу несколько чужих работ из паблика, то может выйти такая ситуация, когда в одной работе функции названы в стиле snake_case, а в другой - в UpperCamelCase, в одной переменные названы в lowerCamelCase, в другой - в lowercase (без разделяющих подчёркиваний). Это будет всё равно, что собирать Франкенштейна из совершенно разных кусков плоти.
Поэтому самовыражение самовыражением, но допустить беспорядка в выкладываемых на p-p работах я не могу.




Но все же, это не так уж затруднит понимание код следующим программистом.

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

Desulaid
14.11.2015, 22:34
Daniel_Cortez, здесь и нет ничего плохого, просто на вики встречаются большинство примеров с UpperCamelCase, собственно поэтому я и написал то что написал))
PS. исправил :dance:

Desulaid
30.11.2015, 21:12
Обновил тему ;)

$continue$
30.11.2015, 22:01
А, с чего ты решил, что у пользователя подключен mxINI?
А, с чего ты решил, что у пользователя подключен sscanf?
А, с чего ты решил, что у пользователя подключен DC_CMD?

Desulaid
30.11.2015, 22:05
Про sscanf: го функцию на получение чисел после запятой.

sscanf(inputtext, "p<,>iii", restart_hour, restart_minute, restart_second);

А про остальное - простота и удобство в использовании!

PS. ради меня подключат, кроме того, 2/3 инклудов распространены и встречаются почти везде, mxINI тоже, но реже стал видеться.