PDA

Просмотр полной версии : [Вопрос] set&getData без учета string,float etc...



Jeff_Monson
26.12.2015, 10:39
Всем привет!
Не знал как назвать тему так что заранее прошу прощения.
Я решил сделать функции наподобие setElementData, getElementData (аля MTA), но столкнулся проблемой.
Не знаю как объяснить, попытаюсь объяснить кодом
У меня есть enum для игрока с разными переменными.


enum player_data {
Name[MAX_PLAYER_NAME+1],//string
Pass[32],//string
Ip[16],//string
bool:Logged,//bool
Float:X,//Float
Float:Y,//Float
Float:Z,//Float
Level//Integer
}
new pData[MAX_PLAYERS][player_data];

И я к ним "сделал" универсальные функции


stock _setData(playerid, data, value) {
if (pData[playerid][data]) {// если data имеются в enum
pData[playerid][data] = value;//меняем значение data
}
}

stock _getData(playerid, data) {
if (pData[playerid][data]) {// если data имеются в enum
return pData[playerid][data];// возвращаем data
}
}

Я знаю что функции сейчас не будут работать ибо функции будут работают только с integer данными т.е номерными.


_setData(playerid, Level, 2)//меняем игроку лвл
_getData(playerid, Level)//узнаем лвл игрока

Есть ли способ заставить работать эти функции и с другими видами? я имею ввиду (integer, strin, float, bool и т.д).


_setData(playerid, Logged, true)//
_getData(playerid, Logged)//
//etc

p.s возможно кто то спросить зачем это мне, мне так удобней.
Заранее спасибо за ответ.

Daniel_Cortez
26.12.2015, 11:36
Накидал простой пример:


#include <a_samp>

const PL_NAME_SIZE = MAX_PLAYER_NAME + 1;
const PL_PASS_HASH_SIZE = 64 + 1;
enum e_PLAYER_INFO
{
plName[PL_NAME_SIZE],
plPassHash[PL_PASS_HASH_SIZE],
bool:plLoginStatus,
plLevel,
plMoney,
plAdminLevel,
Float:plX, Float:plY, Float:plZ
};
new player_info[MAX_PLAYERS][e_PLAYER_INFO];

PrintPlayerInfo(playerid)
{
printf("Name: %s", player_info[playerid][plName]);
printf("PassHash: %s", player_info[playerid][plPassHash]);
static const bool_strs[2][] = {{"false"}, {"true"}};
printf("LoginStatus: %s",bool_strs[!!player_info[playerid][plLoginStatus]]);
printf("Level: %d", player_info[playerid][plLevel]);
printf("Money: %d", player_info[playerid][plMoney]);
printf("AdminLevel: %d", player_info[playerid][plAdminLevel]);
printf("X: %f", player_info[playerid][plX]);
printf("Y: %f", player_info[playerid][plY]);
printf("Z: %f", player_info[playerid][plZ]);
}

SetPlayerField(playerid, e_PLAYER_INFO:field, {_, Float, bool}:value)
player_info[playerid][field] = value;

SetPlayerFieldString(playerid, e_PLAYER_INFO:field, const value[], field_size)
strmid(player_info[playerid][field], value, 0, strlen(value), field_size);

main()
{
SetPlayerFieldString(0, plName, "Daniel_Cortez", PL_NAME_SIZE);
SetPlayerField(0, plLoginStatus, true);
SetPlayerField(0, plLevel, 20);
SetPlayerField(0, plMoney, false);
SetPlayerField(0, plAdminLevel, 9001);
SetPlayerField(0, plX, 2000.0);
SetPlayerField(0, plY, 30.0);
SetPlayerField(0, plZ, 100);
PrintPlayerInfo(0);
}

Обратите внимание: нельзя сделать один и тот же аргумент под одиночное значение и массив, поэтому я сделал отдельную функцию для сохранения строк.
Функции для получения значений, надеюсь, сами доделаете.

И да, в функции SetPlayerField нельзя проверить тег value, поэтому в поле с целочисленным тегом можно передать true или false, а в вещественное поле нечаянно записать целое число. Присмотритесь к записи в поля plMoney и plZ в функции main: я специально ошибся, чтобы показать, что компилятор не заметит никаких ошибок и компилирует код без единого варнинга.

UPD: Попробовал сам сделать функцию GetPlayerField - оказалось не так просто, как могло показаться. Возможно, стоит разделить функции (Get/Set)PlayerField на 6 функций: (Get/Set)PlayerField(Int/Float/Bool). Или каждый раз при использовании GetPlayerField перезаписывать тег возвращаемого значения, если нужно получить bool или Float.
Проще пользоваться массивами, как все нормальные люди - заодно не будет проблем с путаницей тегов значений в SetPlayerValue.

VVWVV
26.12.2015, 11:49
Возможно, стоит разделить функции (Get/Set)PlayerField на 6 функций: (Get/Set)PlayerField(Int/Float/Bool).
Можно разделять теги с помощью функции tagof.

Daniel_Cortez
26.12.2015, 12:26
Можно разделять теги с помощью функции tagof.
В курсе, я даже как-то делал урок на эту тему: http://pro-pawn.ru/showthread.php?12257
И это не функция, а оператор, раз уж на то пошло.

Ок, вот решение с GetPlayerField (к слову, оператор tagof вообще не пригодился):


#include <a_samp>


const PL_NAME_SIZE = MAX_PLAYER_NAME + 1;
const PL_PASS_HASH_SIZE = 64 + 1;
enum e_PLAYER_INFO
{
plName[PL_NAME_SIZE],
plPassHash[PL_PASS_HASH_SIZE],
bool:plLoginStatus,
plLevel,
plMoney,
plAdminLevel,
Float:plX, Float:plY, Float:plZ
};
new player_info[MAX_PLAYERS][e_PLAYER_INFO];


GetPlayerField(playerid, e_PLAYER_INFO:field, &{_, Float, bool}:value)
{
value = player_info[playerid][field];
}

SetPlayerField(playerid, e_PLAYER_INFO:field, {_, Float, bool}:value)
{
player_info[playerid][field] = value;
}

GetPlayerFieldString(playerid,e_PLAYER_INFO:field, buf[],buf_size = sizeof(buf))
{
buf[0] = '\0', strcat(buf, player_info[playerid][field], buf_size);
}

SetPlayerFieldString(playerid, e_PLAYER_INFO:field, const value[], field_size)
{
strmid(player_info[playerid][field], value, 0, strlen(value), field_size);
}


PrintPlayerInfo(playerid)
{
new int_value, float_value, bool_value;
new array_value[128];
static const bool_strs[2][] = {{"false"}, {"true"}};
GetPlayerFieldString(playerid, plName, array_value);
printf("Name: %s", array_value);
GetPlayerFieldString(playerid, plPassHash, array_value);
printf("PassHash: %s", array_value);
GetPlayerField(playerid, plLoginStatus, bool_value);
printf("LoginStatus: %s", bool_strs[!!bool_value]);
GetPlayerField(playerid, plLevel, int_value);
printf("Level: %d", int_value);
GetPlayerField(playerid, plMoney, int_value);
printf("Money: %d", int_value);
GetPlayerField(playerid, plAdminLevel, int_value);
printf("AdminLevel: %d", int_value);
GetPlayerField(playerid, plX, float_value);
printf("X: %f", float_value);
GetPlayerField(playerid, plY, float_value);
printf("Y: %f", float_value);
GetPlayerField(playerid, plZ, float_value);
printf("Z: %f", float_value);
}


main()
{
SetPlayerFieldString(0, plName, "Daniel_Cortez", PL_NAME_SIZE);
new hash[PL_PASS_HASH_SIZE];
format(hash, sizeof(hash), "%x", 0xDC);
SetPlayerFieldString(0, plPassHash, hash, PL_NAME_SIZE);
SetPlayerField(0, plLoginStatus, true);
SetPlayerField(0, plLevel, 20);
SetPlayerField(0, plMoney, false);
SetPlayerField(0, plAdminLevel, 9001);
SetPlayerField(0, plX, 2000.0);
SetPlayerField(0, plY, 30.0);
SetPlayerField(0, plZ, 100);
PrintPlayerInfo(0);
}

В Pawn нельзя сделать функцию, которая может вернуть значение нескольких типов, поэтому пришлось сделать возврат по ссылке.
К тому же, такой подход с установкой и получением значений с помощью функций может отразиться на производительности и повысить использование стека.
Правда, иногда этот подход может пригодиться: например, если массив player_info вынесен в инклуд и объявлен с атрибутом static, чтобы нельзя было получить к нему доступ напрямую из других исходных файлов. Но такое бывает редко, если бывает вообще (лично я ни разу не видел таких модов).

VVWVV
26.12.2015, 12:54
В курсе, я даже как-то делал урок на эту тему: http://pro-pawn.ru/showthread.php?12257
И это не функция, а оператор, раз уж на то пошло.

Да, также, как и оператор return и т.п.
Как вы и сказали, что лучше будет:

Возможно, стоит разделить функции (Get/Set)PlayerField на 6 функций: (Get/Set)PlayerField(Int/Float/Bool)

$continue$
26.12.2015, 13:01
В Pawn нельзя сделать функцию, которая может вернуть значение нескольких типов, поэтому пришлось сделать возврат по ссылке.

Не только в Pawn, в С/C++ такая же ситуация. Без ссылок либо указателей нельзя вернуть более 1 значения (По крайней мере я такого "чуда" пока что не видел)
Ах, да можно еще через структуру.

Daniel_Cortez
26.12.2015, 13:25
Не только в Pawn, в С/C++ такая же ситуация. Без ссылок либо указателей нельзя вернуть более 1 значения (По крайней мере я такого "чуда" пока что не видел)
Ах, да можно еще через структуру.
В C++ хотя бы есть перегрузка функций. В Pawn для такого эффекта приходится танцевать с бубном (ссылка в моём посте выше) и жертвовать производительностью.

Jeff_Monson
26.12.2015, 14:06
Спасибо большое, дело в том что, все это будет лежать в player.inc а использоваться в самом моде.

Проще пользоваться массивами, как все нормальные люди - заодно не будет проблем с путаницей тегов значений в SetPlayerValue.
Ну видать я не нормальный, а если честно да я знаю, я подметил что мне так более удобней, путаница будет в том случай если мод попадет третьим лицам.

Daniel_Cortez
26.12.2015, 14:13
путаница будет в том случай если мод попадет третьим лицам.
Хотите сказать, вы никогда не совершаете ошибок? Ну-ну...

Jeff_Monson
26.12.2015, 14:36
Совершал, если заметить в начале темы strin. но путать money с health или же health c pos думаю глупо.
Хотя совершал) ошибки. именно когда работал с типы данными) но это в прошлом.
Задам еще один вопрос, дабы не создавать каждый раз тему.
Мне надо внутри enum создать переменную с 3мя разными значениями.

enum player_data {
...,
Test[3][MAX_PLAYER_NAME+1]
};
new pData[MAX_PLAYERS][player_data];

main() {
printf("Test 1: %s", pData[0][Test][1]);
printf("Test 2: %s", pData[0][Test][2]);
printf("Test 3: %s", pData[0][Test][3]);
}
Вот только дебаг(компилятор) ругается.
Придется отдельно создавать переменную для таких случай?