PDA

Просмотр полной версии : [Include] licenses.inc Система лицензий в битовой реализации



Prolific
12.05.2016, 12:04
На форуме почти в каждом уроке посвященному битовым операциям упоминается про систему лицензий, которую можно сделать с их помощью, но никто (по крайней мере я не видел) не делал конкретный пример, который можно подключить и пользоваться. Я написал инклуд, который использует всего 1 одномерный массив на MAX_PLAYERS ячеек, который и будет хранить все лицензии.


#include <a_samp>

stock licenses[MAX_PLAYERS];

//Посмотреть лицензию
#define GetLicCar(%0) (licenses[%0] & 1 ? true : false)
#define GetLicPlane(%0) (licenses[%0] & (1<<1) ? true : false)
#define GetLicShip(%0) (licenses[%0] & (1<<2) ? true : false)
#define GetLicBiz(%0) (licenses[%0] & (1<<3) ? true : false)
#define GetLicFish(%0) (licenses[%0] & (1<<4) ? true : false)

//Выдать лицензию
#define GiveLicCar(%0) (licenses[%0] |= 1)
#define GiveLicPlane(%0) (licenses[%0] |= (1<<1))
#define GiveLicShip(%0) (licenses[%0] |= (1<<2))
#define GiveLicBiz(%0) (licenses[%0] |= (1<<3))
#define GiveLicFish(%0) (licenses[%0] |= (1<<4))

//Забрать лицензию
#define TakeLicCar(%0) (licenses[%0] &= ~1)
#define TakeLicPlane(%0) (licenses[%0] &= ~(1<<1))
#define TakeLicShip(%0) (licenses[%0] &= ~(1<<2))
#define TakeLicBiz(%0) (licenses[%0] &= ~(1<<3))
#define TakeLicFish(%0) (licenses[%0] &= ~(1<<4))

#define GetPlayerLicsValue(%0) licenses[%0]
#define SetPlayerLicsValue(%0,%1) (licenses[%0] = %1)


Просто вставляем это в мод, либо подключаем в виде инклуда.

P.S. Хранить в БД нужно всего 1-о число.
Пример сохранения:

mysql_format(DATABASE, string, sizeof(string), "UPDATE `accounts` SET `pLicenses` = %d WHERE `pID` = %d LIMIT 1",
GetPlayerLicsValue(playerid), pInfo[playerid][pID]);

Пример инициализации:

SetPlayerLicsValue(playerid, cache_get_field_content_int(0, "pLicenses", DATABASE));

Daniel_Cortez
12.05.2016, 21:38
Идея хорошая, но реализация, ИМХО, хромает.



#define GetLicCar(%0) (licenses[%0] & 1 ? true : false)
#define GetLicPlane(%0) (licenses[%0] & (1<<1) ? true : false)
#define GetLicShip(%0) (licenses[%0] & (1<<2) ? true : false)
#define GetLicBiz(%0) (licenses[%0] & (1<<3) ? true : false)
#define GetLicFish(%0) (licenses[%0] & (1<<4) ? true : false)

Каждый новый макрос здесь - это повторение предыдущего. Разве что GetLicCar реализован не так, как остальные, но это может только ещё больше сбить с толку.

Мало того, если какой-то вид лицензии не объявлен, мне придётся самому лезть в чужой код, разбираться, как он работает, и добавлять макросы для новых лицензий.
Причём не факт, что эти новые макросы будут добавлены правильно. Если я сделаю макрос на основе уже существующего и забуду поменять название, компилятор выдаст варнинг на повторное определение макроса.
Если же забыть поменять значение сдвига (например, вместо "<<5" оставить "<<4"), ошибка останется незамеченной.


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


// Защита от повторного подключения (актуально при использовании модифицированного компилятора от Zeex).
#if defined PL_LICENSES // Префикс "PL" - сокращение от "Prolific", можете выбрать и другой.
#endinput
#endif
#define PL_LICENSES

#include <a_samp>


// Макросы для работы с флагами.
#if !defined BitGet
#define BitGet(%0,%1)\
(%0) & (1 << (%1))
#endif
#if !defined BitSet
#define BitSet(%0,%1,%2)\
%0 = ((%2) != 0) ? ((%0) | (1 << (%1))) : ((%0) & ~(1 << (%1)))
#endif


#if !defined e_LICENSE_TYPE
// Допускаем возможность самостоятельного объявления лицензий на случай, если пользователю нужен тип лицензии,
// которого нет в инклуде (например, здесь не объявлена лицензия на ведение бизнеса).
enum e_LICENSE_TYPE
{
LICENSE_TYPE_FISHING,
LICENSE_TYPE_DRIVING,
LICENSE_TYPE_PILOT
};
#endif

// Если типов лицензий не больше восьми, можно использовать упакованный массив.
// Спецификатор static ограничивает видимость переменной в пределах инклуда.
static stock licenses[MAX_PLAYERS char];


// Функции для операций с лицензиями.
// Здесь нужны именно функции, а не макросы, чтобы компилятор мог выдать варнинг,
// если, например, вместо "LICENSE_TYPE_FISHING" передать "0".
stock GetPlayerLicenseStatus(playerid, e_LICENSE_TYPE:type)
return BitGet(licenses{playerid}, _:type);

stock SetPlayerLicenseStatus(playerid, e_LICENSE_TYPE:type, bool:active)
return BitSet(licenses{playerid}, _:type, _:active);

stock GivePlayerLicense(playerid, e_LICENSE_TYPE:type)
return BitSet(licenses{playerid}, _:type, 1);

stock TakePlayerLicense(playerid, e_LICENSE_TYPE:type)
return BitSet(licenses{playerid}, _:type, 0);

stock GetPlayerLicenses(playerid)
return licenses{playerid};

stock SetPlayerLicenses(playerid, flags)
return (licenses{playerid} = flags);

L0ndl3m
12.05.2016, 21:51
#if !defined BitGet
#define BitGet(%0,%1)\
%0 &= (1 << (%1))
#endif


Ошибка? Получаем же значение флага.

Daniel_Cortez
12.05.2016, 21:52
Ошибка? Получаем же значение флага.
Да, верно. Час ночи, что сказать... Хорошо хоть, что не релиз.

Prolific
12.05.2016, 22:41
Идея хорошая, но реализация, ИМХО, хромает.

Каждый новый макрос здесь - это повторение предыдущего. Разве что GetLicCar реализован не так, как остальные, но это может только ещё больше сбить с толку.

Мало того, если какой-то вид лицензии не объявлен, мне придётся самому лезть в чужой код, разбираться, как он работает, и добавлять макросы для новых лицензий.
Причём не факт, что эти новые макросы будут добавлены правильно. Если я сделаю макрос на основе уже существующего и забуду поменять название, компилятор выдаст варнинг на повторное определение макроса.
Если же забыть поменять значение сдвига (например, вместо "<<5" оставить "<<4"), ошибка останется незамеченной.


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


// Защита от повторного подключения (актуально при использовании модифицированного компилятора от Zeex).
#if defined PL_LICENSES // Префикс "PL" - сокращение от "Prolific", можете выбрать и другой.
#endinput
#endif
#define PL_LICENSES

#include <a_samp>


// Макросы для работы с флагами.
#if !defined BitGet
#define BitGet(%0,%1)\
(%0) & (1 << (%1))
#endif
#if !defined BitSet
#define BitSet(%0,%1,%2)\
%0 = ((%2) != 0) ? ((%0) | (1 << (%1))) : ((%0) & ~(1 << (%1)))
#endif


#if !defined e_LICENSE_TYPE
// Допускаем возможность самостоятельного объявления лицензий на случай, если пользователю нужен тип лицензии,
// которого нет в инклуде (например, здесь не объявлена лицензия на ведение бизнеса).
enum e_LICENSE_TYPE
{
LICENSE_TYPE_FISHING,
LICENSE_TYPE_DRIVING,
LICENSE_TYPE_PILOT
};
#endif

// Если типов лицензий не больше восьми, можно использовать упакованный массив.
// Спецификатор static ограничивает видимость переменной в пределах инклуда.
static stock licenses[MAX_PLAYERS char];


// Функции для операций с лицензиями.
// Здесь нужны именно функции, а не макросы, чтобы компилятор мог выдать варнинг,
// если, например, вместо "LICENSE_TYPE_FISHING" передать "0".
stock GetPlayerLicenseStatus(playerid, e_LICENSE_TYPE:type)
return BitGet(licenses{playerid}, _:type);

stock SetPlayerLicenseStatus(playerid, e_LICENSE_TYPE:type, bool:active)
return BitSet(licenses{playerid}, _:type, _:active);

stock GivePlayerLicense(playerid, e_LICENSE_TYPE:type)
return BitSet(licenses{playerid}, _:type, 1);

stock TakePlayerLicense(playerid, e_LICENSE_TYPE:type)
return BitSet(licenses{playerid}, _:type, 0);

stock GetPlayerLicenses(playerid)
return licenses{playerid};

stock SetPlayerLicenses(playerid, flags)
return (licenses{playerid} = flags);


В любом случае нужно лезть в инклуд для добавления значений в enum, либо выносить его в мод, но это уже противоречит твоей цели, DC. В целом твой вариант более гибкий, not bad.

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

P.S.
// если, например, вместо "LICENSE_TYPE_FISHING" передать "0".
Какая разница что мы передаем 0 или LICENSE_TYPE_FISHING?

TheMallard
13.05.2016, 03:51
А флаг зачем тогда придумывать? Да и в PlayerInfo можно 0 задействовать, не спорю.

Daniel_Cortez
13.05.2016, 15:56
В любом случае нужно лезть в инклуд для добавления значений в enum, либо выносить его в мод, но это уже противоречит твоей цели, DC.
Не нужно. Не зря ж объявление e_LICENSE_TYPE заключено в #if - если объявить такой тег до подключения инклуда, будет использоваться пользовательский набор лицензий.


enum e_LICENSE_TYPE
{
LICENSE_TYPE_FISHING,
LICENSE_TYPE_DRIVING,
LICENSE_TYPE_PILOT,
LICENSE_TYPE_BUSINESS,
LICENSE_TYPE_BOATING,
LICENSE_TYPE_BREATH
};
#include "../include/licenses.inc"





P.S.
// если, например, вместо "LICENSE_TYPE_FISHING" передать "0".
Какая разница что мы передаем 0 или LICENSE_TYPE_FISHING?
Ну вы ж не будете наизусть заучивать номера лицензий. Наверняка в вашем моде полно и других вещей, которые нужно постоянно держать в голове - зачем создавать себе ещё одну проблему?

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

В то же время благодаря разным тегам можно осуществлять контроль над передаваемыми значениями: если на входе у функции не константа LICENSE_TYPE_*, то это, скорее всего, ошибка.

Prolific
13.05.2016, 18:22
Где я сказал, что теги не нужны???!!! Я сказал лишь в чем разница и почему бы и нет, вы тут как всегда раздули из мухи слона, + показали свое ЧСВ, ведь естественно у всех гавнокод кроме вас любимых, относился всегда к этому с юмором, но тут что не ответ то показываение своего ЧСВ. Смотрите, а то так не заметите как Окстайлами станете.

Daniel_Cortez
13.05.2016, 20:24
Где я сказал, что теги не нужны???!!!
Успокойтесь. Откуда мне знать, что именно вы знаете, а что нет?
Поскольку я ещё не делал никаких уроков с описанием нюансов в плане создания инклудов, я постарался подробно ответить на вопрос в этой теме, да и не столько ради вас, сколько ради других пользователей, которые тоже могут подчерпнуть отсюда новых знаний. Зачем сразу так бурно реагировать?



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

Prolific
14.05.2016, 14:52
Успокойтесь. Откуда мне знать, что именно вы знаете, а что нет?
Поскольку я ещё не делал никаких уроков с описанием нюансов в плане создания инклудов, я постарался подробно ответить на вопрос в этой теме, да и не столько ради вас, сколько ради других пользователей, которые тоже могут подчерпнуть отсюда новых знаний. Зачем сразу так бурно реагировать?



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

Раз часть текста адресована не мне, то я спокоен.
(Подгарел пукан, приношу извинения)

Unreal
19.05.2016, 14:22
Можно подробный урок о 'битовых кодах'. Я уже читал и появились куча непонятных мне вопросов на которых не нашел ответа.

$continue$
19.05.2016, 15:58
Тогда хабра-юзеры ЧСВшники в чистом виде. Аминь.

но тут что не ответ то показываение своего ЧСВ

Prolific
19.05.2016, 21:50
Можно подробный урок о 'битовых кодах'. Я уже читал и появились куча непонятных мне вопросов на которых не нашел ответа.

Я реально пока не дорос до уроков, я считаю, проси более опытных людей, либо задавай свои вопросы мне в ЛС.

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

$continue$
19.05.2016, 22:45
Например, тут (https://tproger.ru/translations/bitwise-operations/).

Можно подробный урок о 'битовых кодах'. Я уже читал и появились куча непонятных мне вопросов на которых не нашел ответа.