> > > > >

F.A.Q. по скриптингу by sbelov020

Сообщения
422
Рейтинг
82
#1
Итак, наконец у меня дошли руки создать данную тему.
Предпосылки к созданию: https://dev-cs.ru/threads/4242/

Краткое описание: в этой теме я буду задавать интересующие меня вопросы по скриптингу, а после получения ответа, (если Sonyx немного поможет мне с таймингом редактирования поста:smile3:) ответы будут размещаться здесь, в шапке темы, по виду:

Q: Вопрос
A: (автор ответа) Ответ

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

Итак, мой первый вопрос: какое меню лучше? Которое создается через menu_create (я так понял, это т.н. "новое" меню?), или через register_menu? Попрошу дать развернутый ответ, почему то или иное меню лучше.

/* Начало F.A.Q. */
  • Q: Какое меню лучше? "Старое" или "новое"?
  • A: BlackSignature, gyxoBka: Это зависит от требуемых задач. Зачастую "новое" меню не может выполнить те задачи, которые может выполнить "старое", но иногда всё-же наоборот, удобнее использовать "новое" меню.

  • Q: В чём разница между static и new const?
  • A: BlackSignature: const делает переменную/массив read-only, т.е. можно читать, но нельзя изменять.
    static создаёт переменную при первом обращении в функции, и после завершения функции переменная не удаляется, т.е. сохраняет своё текущее значение.
    1) В очень часто вызываемых функциях (каллбеки пофреймовых хуков вроде PreThink, AddToFullPack и т.п.) позволяет сэкономить процессорное время на создании переменных/массивов. Особенно актуально для последних (чем они больше, тем больше выигрыш).
    2) Сохранение значения в локальных масштабах (в пределах функции).

  • Q; Что такое #pragma, и какие они бывают?
  • A; wopox1337: это директивы препроцессора. Диктуют компилятору условия.
 
Последнее редактирование:
 
Сообщения
215
Рейтинг
420
#2
Итак, мой первый вопрос: какое меню лучше? Которое создается через menu_create (я так понял, это т.н. "новое" меню?), или через register_menu? Попрошу дать развернутый ответ, почему то или иное меню лучше.
Вопрос не совсем понятен. Что подразумевается под "лучше"? Всё всегда зависит от задачи, а в данном случае, ещё и от предпочтения. Многостраничные меню (особенно, динамические, т.е. меняющиеся), как по мне, удобнее делать через систему "нового меню". Но это не всегда так, всё зависит от условий.
 
1  
Сообщения
105
Рейтинг
119
#3
Новая система меню это лишь обертка для "старого" меню и зачастую на новом меню нетипичные задачи не решить.
 
2  
Сообщения
422
Рейтинг
82
#4
BlackSignature, "лучше" для меня, в данном случае, удобнее, полезнее, надежнее.
Потому что сейчас я все свои меню пишу по старой системе. Вот и думаю, может я совершаю ошибку, и давно пора использовать новые меню?
15 Дек 2018
gyxoBka, иначе говоря, особой разницы нет? Кроме нюансов
15 Дек 2018
BlackSignature, вот у меня как раз в одном плагине многостраничное меню, в другом динамическое меню. (С переключателями вкл/выкл) сейчас они реализованы как несколько меню (страницы) и if-else для переключателей. Стоит переписать эти меню по новой системе?
 
 
Сообщения
215
Рейтинг
420
#5
sbelov020, На данном этапе используйте тот вариант, который удобнее вам. Просто покажу пример старой системы, где при генерации составляется меню игроков + технические пункты, которые в системе "нового" меню описывались бы проще (меньше кода). В новой системе так же проще с определением страницы. Однако, конкретно этот вариант имеет ряд нюансов, которые не позволяют заюзать тут "новое меню" без лишних заморочек. Духовка верно подметил. Чем сложнее собирается меню, тем сложнее с ним работать при помощи "новой" системы.

Код:
stock func_TransferMenu(id, iPage = _PAGE1_) {
    new iPlayerCount, iPlayer

    for(iPlayer = 1; iPlayer <= MaxClients; iPlayer++) {
        if(iPlayer == id || !ps_is_player_loaded(iPlayer)) {
            continue
        }

        g_iPlayers[id][iPlayerCount] = iPlayer
        g_iPlayerIDs[id][iPlayerCount] = get_user_userid(iPlayer)
        iPlayerCount++
    }

    new i = min(iPage * ITEMS_PER_PAGE__TRANSFER_MENU, iPlayerCount)
    new iStart = i - (i % ITEMS_PER_PAGE__TRANSFER_MENU)
    new iEnd = min(iStart + ITEMS_PER_PAGE__TRANSFER_MENU, iPlayerCount)

    g_iMenuPage[id] = iPage = iStart / ITEMS_PER_PAGE__TRANSFER_MENU

    new iPos, iMenuItem, iKeys = MENU_KEY_0,
        iPagesNum = max(1, (iPlayerCount / ITEMS_PER_PAGE__TRANSFER_MENU + ((iPlayerCount % ITEMS_PER_PAGE__TRANSFER_MENU) ? 1 : 0)))

    new iCommission = g_eCvar[CVAR__COMM_PERCENT_USER], iFlags = get_user_flags(id)

    if(iFlags & g_eCvar[CVAR__SUPERVIP_FLAG]) {
        iCommission = g_eCvar[CVAR__COMM_PERCENT_SUPERVIP]
    }
    else if(iFlags & g_eCvar[CVAR__VIP_FLAG]) {
        iCommission = g_eCvar[CVAR__COMM_PERCENT_VIP]
    }

    new iLen = formatex( g_szMenu, chx(g_szMenu),
        "\yВыберите получателя [%d/%d]^n\
        \wУ вас \y%d \wочков \y(комиссия %d%%)^n^n",

        iPage + 1, iPagesNum,
        ps_get_points(id), iCommission
    );

    for(i = iStart; i < iEnd; i++) {
        iKeys |= (1 << iMenuItem)
        iPlayer = g_iPlayers[id][i]
        iLen += formatex(g_szMenu[iLen], chx(g_szMenu) - iLen, "\y%d. \w%n^n", ++iMenuItem, iPlayer)
    }

    if(!iMenuItem) {
        if(iPage) {
            return func_TransferMenu(id, --iPage)
        }

        g_iPlayers[id][0] = 0
        iKeys |= MENU_KEY_1
        iLen += formatex(g_szMenu[iLen], chx(g_szMenu) - iLen, "\y1. \dНет подходящих \y[обновить]")
    }

    if(iPage) {
        iPos++
        iKeys |= MENU_KEY_8
        iLen += formatex(g_szMenu[iLen], chx(g_szMenu) - iLen, "^n\y8. Назад")
    }

    if(iEnd < iPlayerCount)    {
        iPos++
        iKeys |= MENU_KEY_9
        iLen += formatex(g_szMenu[iLen], chx(g_szMenu) - iLen, "^n\y9. Далее")
    }

    formatex(g_szMenu[iLen], chx(g_szMenu) - iLen, "%s^n\y0. Выход", iPos ? "^n" : "")

    return func_ShowMenu(id, iKeys, MENU_MODE__TRANSFER)
}

stock func_TransferMenu_SubHandler(id, iKey) {
    new iMenuPage = g_iMenuPage[id]

    switch(iKey) {
        case _KEY8_: func_TransferMenu(id, --iMenuPage)
        case _KEY9_: func_TransferMenu(id, ++iMenuPage)
        case _KEY0_: return PLUGIN_HANDLED
        default: { // _KEY1_.._KEY7_
            new iPos = (iMenuPage * ITEMS_PER_PAGE__TRANSFER_MENU) + iKey
            new iTarget = g_iPlayers[id][iPos]
            new iTargetID = get_user_userid(iTarget) // SafeToUse для отключённых (возвращает -1)

            if(iTargetID != g_iPlayerIDs[id][iPos] || !g_iPlayers[id][0] || !ps_is_player_loaded(id))
                return func_TransferMenu(id, iMenuPage)

            g_iTarget[id] = iTarget
            g_iPlayerIDs[id][0] = iTargetID
            g_iInputMode[id] = INPUT_MODE__TRANSFER

            rg_send_audio(id, SOUND__BLIP1)
            client_print_color(id, iTarget, "^4* ^1Напишите в чат, сколько очков вы хотите передать игроку^3 %n", iTarget)
            client_print_color(id, print_team_default, "^4* ^1Если передумаете, напишите^4 %s ^1для отмены запроса", g_szCancelCmd)
        }
    }

    return PLUGIN_HANDLED
}
 
1  
Сообщения
100
Рейтинг
85
#6
В новом меню нельзя поставить номер пункта в квадратные скобочки :smile3:
 
 
Сообщения
422
Рейтинг
82
#7
Следующий вопрос: в чём разница между static и new const?
 
Последнее редактирование:
 
Сообщения
215
Рейтинг
420
#8
sbelov020, const делает переменную/массив read-only, т.е. можно читать, но нельзя изменять.
Вне функций нет разницы, static или new используйте new (причина через один пост ниже)
Внутри функции:
new заново создаёт переменную при каждом обращении к функции, и соотвественно, после завершения функции переменная удаляется, освобождая занятую память (значение пропадает).
static создаёт переменную при первом обращении в функции, и после завершения функции переменная не удаляется, т.е. сохраняет своё текущее значение.

Практическая польза от static внутри функции:
1) В очень часто вызываемых функциях (каллбеки пофреймовых хуков вроде PreThink, AddToFullPack и т.п.) позволяет сэкономить процессорное время на создании переменных/массивов. Особенно актуально для последних (чем они больше, тем больше выигрыш).
2) Сохранение значения в локальных масштабах (в пределах функции).
Код:
#include <amxmodx>

public plugin_init() {
    register_srvcmd("test", "myfunc")
}

public myfunc() {
    static iStatic
    new iNonStatic
  
    server_print("BEFORE -> iStatic: %d | iNonStatic: %d", iStatic, iNonStatic)
  
    iStatic++
    iNonStatic++

    server_print("AFTER -> iStatic: %d | iNonStatic: %d", iStatic, iNonStatic)
}
 
Последнее редактирование:
2  
Сообщения
339
Рейтинг
583
#9
В очень часто вызываемых функциях (каллбеки пофреймовых хуков вроде PreThink, AddToFullPack и т.п.) позволяет сэкономить процессорное время на создании переменных/массивов. Особенно актуально для последних (чем они больше, тем больше выигрыш).
Мнимый выигрыш, мало чем подтвержденный. Что будет, если статик осел в ОЗУ, а new в кэш процессора?
 
1  
Сообщения
215
Рейтинг
420
#11
Mistrick, может и так. Я не мерил, просто рассказал о применении как "деды с оленей завещали".
wopox1337, Какие файлы? Не понял. Переменная, объявленная в пределах функции, недоступна за пределами этой функции, если только она прямо не передаётся из этой функции куда-то наружу в виде аргумента. Ну это ты и так знаешь, это я ТС'у, чтобы понимал. :)
 
 
Сообщения
215
Рейтинг
420
#13
wopox1337, Да, проверил, так и есть. Не знал об этом, т.к. никогда статики вне функций не использовал.
 
 
Сообщения
2.015
Рейтинг
1948
#15
Если я правильно понял вопрос.
Код:
#define FIELD "Field #1"
или
new const FIELD[] = "Field #1";
То, лучше пользоваться вариантом new const. Почему? Проблемы компилятора AMXX по сей день не решены, хоть и не критичны.
Цитата от Prostotema:
Для строк в AMXX лучше использовать константы, потому что компилятор настолько божественен, что он записывает несколько одинаковых строчек (если это не константы) в .DATA
В компиляторах C++ такого мне не встречалось.
P.S: только не в угоду функциональности. (Там, где комментированием макроса можно повлиять на настройку)
 
1  
Сообщения
422
Рейтинг
82
#16
Если я правильно понял вопрос.
про дефайн тоже интересно, но

new const это только для массива?

меня интересует разница между объявлением аргументов через constили static
 
 
Сообщения
215
Рейтинг
420
#17
sbelov020, я же объяснил уже всё. const означает что значение после инициализации уже нельзя изменить. А static, созданный в рамках функции, означает что "объект" не удаляется из памяти, а продолжает в ней висеть, и при следующем к нему обращении(при чтении) можно получить его значение, которое никуда не делось.
new iVar = 1
const iVar = 1
static iVar = 1
static const iVar = 1
Суньте себе в тестовый плагин и поиграйтесь (запись, чтение), и всё станет ясно.
 
1  
Сообщения
422
Рейтинг
82
#19
Следующий вопрос:

Объясните, пожалуйста, что такое, какие бывают #pragma, и в каких случаях их нужно применять?

Пока что знаю только #pragma semicolon 1 - чтоб компилятор был требователен к точкам с запятой после каждой строки
и #pragma tabsize 0 - при компиляции размер табуляции устанавливается в 0.

Еще видел #pramga unused <..> - это чтоб в какой-то функции не использовать указанные аргументы?

И еще где-то видел #pragma compress 1 - но что он делает, мне не ясно.
 
 

Похожие темы

> > > > >