Вход

Просмотр полной версии : [Вопрос] Проблема с GetPlayerHealth



m1n1vv
02.07.2016, 20:18
Почему GetPlayerHealth не корректно показывает информацию о хп? Для теста поставил себе 8 с чем-то тысяч здоровья, но выводит далеко не эти числа.

new
Float:health;
GetPlayerHealth(playerid, health);
printf("HP: %.0f, %.0f", pInfo[playerid][pHealth], health);

HP: 8562, 114
Это баг или я что-то не так делаю?

P.S. На деле выдало 8562 хп. Проверял на взрывах )

Nexius_Tailer
02.07.2016, 20:37
* Even though the health can be set to near infinite values on the server side, the individual clients will only report values up to 255. Anything higher will wrap around; 256 becomes 0, 257 becomes 1, etc.
Фича такая: за 255 значением следует "количество хп - 256"

Deni$
02.07.2016, 20:38
А если вот так попробовать?


new
Float:health;
GetPlayerHealth(playerid, health);
printf("{HP: %.0f, %.0f},", pInfo[playerid][pHealth], health);

L0ndl3m
02.07.2016, 20:54
Фича такая: за 255 значением следует "количество хп - 256"
Неверно перевели.
Все значения которые идут после 255 корректируются как (не дословный перевод, но понятный):


256 -> 0
257 -> 1
258 -> 2

m1n1vv
02.07.2016, 21:34
Есть выход с ситуации?

ziggi
02.07.2016, 21:50
Есть выход с ситуации?

Перехват GetPlayerHealth с целью подмены значения и собственная система урона.

Daniel_Cortez
02.07.2016, 21:51
Есть выход с ситуации?
Только если сделать что-то типа античита - перехватить вызовы Get/SetPlayerHealth и контролировать HP на стороне сервера.

Nexius_Tailer
02.07.2016, 21:58
Неверно перевели.
Все значения которые идут после 255 корректируются как (не дословный перевод, но понятный):


256 -> 0
257 -> 1
258 -> 2

Я написал о том же


А если вот так попробовать?


new
Float:health;
GetPlayerHealth(playerid, health);
printf("{HP: %.0f, %.0f},", pInfo[playerid][pHealth], health);
Со скобками ж просто выведет, толку то)

m1n1vv
02.07.2016, 22:41
Ну SetPlayerHealth это не коснулось

Nexius_Tailer
03.07.2016, 00:31
А вот просто использовать переменную pInfo[playerid][pHealth] ненадежно?
Надёжно, но тогда если где-нибудь сверить хп в переменной и только что узнанное хп, то они не будут совпадать даже будучи реально равными. Если такая проверка где-то будет, то вот пример, как сделать чтобы она работала корректно:

//Где-нибудь
SetPlayerHealth(playerid, 10000);
pInfo[playerid][pHealth] = 10000;


new Float:hp;
GetPlayerHealth(playerid, hp);
while(pInfo[playerid][pHealth] > hp + 255) hp += 256;
//нужные нам проверки
//(теперь переменная с новым хп "hp" будет с правильным значением)

//Ну и если это какой-нибудь таймер и нам нужно обновить старое хп, просто делаем следующее
pInfo[playerid][pHealth] = floatround(hp, floatround_tozero);

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

m1n1vv
03.07.2016, 15:19
Надёжно, но тогда если где-нибудь сверить хп в переменной и только что узнанное хп, то они не будут совпадать даже будучи реально равными. Если такая проверка где-то будет, то вот пример, как сделать чтобы она работала корректно:

//Где-нибудь
SetPlayerHealth(playerid, 10000);
pInfo[playerid][pHealth] = 10000;


new Float:hp;
GetPlayerHealth(playerid, hp);
while(pInfo[playerid][pHealth] > hp + 255) hp += 256;
//нужные нам проверки
//(теперь переменная с новым хп "hp" будет с правильным значением)

//Ну и если это какой-нибудь таймер и нам нужно обновить старое хп, просто делаем следующее
pInfo[playerid][pHealth] = floatround(hp, floatround_tozero);

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

Спасибо. Но почему-то не всегда точно выдает. В базе я ставлю одно значение. А выводит на сотню с чем то больше, иногда меньше ста.

БД: 6463
Лог сервера: 6656, 6656

И правильно ли это сделал?

stock nh_GetPlayerHealth(playerid, &Float:health)
{
while(pInfo[playerid][pHealth] > health + 255) health += 256;
return 1;
}
#if defined _ALS_GetPlayerHealth
#undef GetPlayerHealth
#else
#define _ALS_GetPlayerHealth
#endif
#define GetPlayerHealth nh_GetPlayerHealth

Система урона есть

Nexius_Tailer
03.07.2016, 17:16
stock nh_GetPlayerHealth(playerid, &Float:health)
{
while(pInfo[playerid][pHealth] > health + 255) health += 256;
return 1;
}
#if defined _ALS_GetPlayerHealth
#undef GetPlayerHealth
#else
#define _ALS_GetPlayerHealth
#endif
#define GetPlayerHealth nh_GetPlayerHealth

Система урона есть
Наверное ошибка


stock nh_GetPlayerHealth(playerid, &Float:health)
{
if(!IsPlayerConnected(playerid)) return 0;
GetPlayerHealth(playerid, health); //<-
while(pInfo[playerid][pHealth] > health + 255) health += 256;
return 1;
}
#if defined _ALS_GetPlayerHealth
#undef GetPlayerHealth
#else
#define _ALS_GetPlayerHealth
#endif
#define GetPlayerHealth nh_GetPlayerHealth

Хотя если задумано именно подменять хп на серверное, то тогда можно просто возвращать pHealth, оно ведь и так имеет "правильное" значение с хп

P.s. Проверил, число 6656 вместо 6463 из-за того, что к нулю (&health скорее всего будет с таким значением) прибавляется несколько раз 256 (6656 это 256 * 26)

m1n1vv
03.07.2016, 18:27
С хп меньше 500 все время выдает 256

ziggi
03.07.2016, 19:37
Вы совсем не то делаете.

В общем, вот скрипт:


/*
About: custom health system
Author: ziggi
*/

/*
Defines
*/

#define MAX_PLAYER_HEALTH 1000.0

/*
Vars
*/

static
Float:gPlayerHealth[MAX_PLAYERS];

/*
SetPlayerHealth(playerid, Float:health)
*/

stock CustomHealth_SetPlayerHealth(playerid, Float:health)
{
if (!IsPlayerConnected(playerid)) {
return 0;
}

if (health > MAX_PLAYER_HEALTH) {
health = MAX_PLAYER_HEALTH;
} else if (health < 0.0) {
health = 0.0;
}

gPlayerHealth[playerid] = health;
return SetPlayerHealth(playerid, health / MAX_PLAYER_HEALTH * 100.0);
}
#if defined _ALS_SetPlayerHealth
#undef SetPlayerHealth
#else
#define _ALS_SetPlayerHealth
#endif

#define SetPlayerHealth CustomHealth_SetPlayerHealth


/*
GetPlayerHealth(playerid, &Float:health)
*/

stock CustomHealth_GetPlayerHealth(playerid, &Float:health)
{
if (!IsPlayerConnected(playerid)) {
return 0;
}

health = gPlayerHealth[playerid];
return 1;
}
#if defined _ALS_GetPlayerHealth
#undef GetPlayerHealth
#else
#define _ALS_GetPlayerHealth
#endif

#define GetPlayerHealth CustomHealth_GetPlayerHealth

/*
OnPlayerTakeDamage(playerid, issuerid, Float:amount, weaponid, bodypart)
*/

public OnPlayerTakeDamage(playerid, issuerid, Float:amount, weaponid, bodypart)
{
if (issuerid == INVALID_PLAYER_ID) {
SetPlayerHealth(damagedid, gPlayerHealth[playerid] - amount);
}

#if defined CustomHealth_OnPlayerTakeDamage
return CustomHealth_OnPlayerTakeDamage(playerid, issuerid, amount, weaponid, bodypart);
#else
return 1;
#endif
}
#if defined _ALS_OnPlayerTakeDamage
#undef OnPlayerTakeDamage
#else
#define _ALS_OnPlayerTakeDamage
#endif

#define OnPlayerTakeDamage CustomHealth_OnPlayerTakeDamage
#if defined CustomHealth_OnPlayerTakeDamage
forward CustomHealth_OnPlayerTakeDamage(playerid, issuerid, Float:amount, weaponid, bodypart);
#endif

/*
OnPlayerGiveDamage(playerid, damagedid, Float:amount, weaponid, bodypart)
*/

public OnPlayerGiveDamage(playerid, damagedid, Float:amount, weaponid, bodypart)
{
if (damagedid != INVALID_PLAYER_ID) {
new
Float:armour,
Float:difference;

GetPlayerArmour(damagedid, armour);

difference = armour - amount;

if (difference > 0.0) {
SetPlayerArmour(damagedid, difference);
} else {
SetPlayerArmour(damagedid, 0.0);
SetPlayerHealth(damagedid, gPlayerHealth[playerid] + difference);
}
}

#if defined CustomHealth_OnPlayerGiveDamage
return CustomHealth_OnPlayerGiveDamage(playerid, damagedid, amount, weaponid, bodypart);
#else
return 1;
#endif
}
#if defined _ALS_OnPlayerGiveDamage
#undef OnPlayerGiveDamage
#else
#define _ALS_OnPlayerGiveDamage
#endif

#define OnPlayerGiveDamage CustomHealth_OnPlayerGiveDamage
#if defined CustomHealth_OnPlayerGiveDamage
forward CustomHealth_OnPlayerGiveDamage(playerid, damagedid, Float:amount, weaponid, bodypart);
#endif

/*
OnPlayerSpawn(playerid)
*/

public OnPlayerSpawn(playerid)
{
SetPlayerTeam(playerid, 0);

#if defined CustomHealth_OnPlayerSpawn
return CustomHealth_OnPlayerSpawn(playerid);
#else
return 1;
#endif
}
#if defined _ALS_OnPlayerSpawn
#undef OnPlayerSpawn
#else
#define _ALS_OnPlayerSpawn
#endif

#define OnPlayerSpawn CustomHealth_OnPlayerSpawn
#if defined CustomHealth_OnPlayerSpawn
forward CustomHealth_OnPlayerSpawn(playerid);
#endif

Но в идеале нужно ещё реализовать собственную team систему.

P.S. Код не тестировал и не компилировал.

m1n1vv
03.07.2016, 19:39
Вы совсем не то делаете.

В общем, вот скрипт:


/*
About: custom health system
Author: ziggi
*/

/*
Defines
*/

#define MAX_PLAYER_HEALTH 1000.0

/*
Vars
*/

static
Float:gPlayerHealth[MAX_PLAYERS];

/*
SetPlayerHealth(playerid, Float:health)
*/

stock CustomHealth_SetPlayerHealth(playerid, Float:health)
{
if (!IsPlayerConnected(playerid)) {
return 0;
}

if (health > MAX_PLAYER_HEALTH) {
health = MAX_PLAYER_HEALTH;
} else if (health < 0.0) {
health = 0.0;
}

gPlayerHealth[playerid] = health;
return SetPlayerHealth(playerid, health / MAX_PLAYER_HEALTH * 100.0);
}
#if defined _ALS_SetPlayerHealth
#undef SetPlayerHealth
#else
#define _ALS_SetPlayerHealth
#endif

#define SetPlayerHealth CustomHealth_SetPlayerHealth


/*
GetPlayerHealth(playerid, &Float:health)
*/

stock CustomHealth_GetPlayerHealth(playerid, &Float:health)
{
if (!IsPlayerConnected(playerid)) {
return 0;
}

health = gPlayerHealth[playerid];
return 1;
}
#if defined _ALS_GetPlayerHealth
#undef GetPlayerHealth
#else
#define _ALS_GetPlayerHealth
#endif

#define GetPlayerHealth CustomHealth_GetPlayerHealth

/*
OnPlayerTakeDamage(playerid, issuerid, Float:amount, weaponid, bodypart)
*/

public OnPlayerTakeDamage(playerid, issuerid, Float:amount, weaponid, bodypart)
{
if (issuerid == INVALID_PLAYER_ID) {
SetPlayerHealth(damagedid, gPlayerHealth[playerid] - amount);
}

#if defined CustomHealth_OnPlayerTakeDamage
return CustomHealth_OnPlayerTakeDamage(playerid, issuerid, amount, weaponid, bodypart);
#else
return 1;
#endif
}
#if defined _ALS_OnPlayerTakeDamage
#undef OnPlayerTakeDamage
#else
#define _ALS_OnPlayerTakeDamage
#endif

#define OnPlayerTakeDamage CustomHealth_OnPlayerTakeDamage
#if defined CustomHealth_OnPlayerTakeDamage
forward CustomHealth_OnPlayerTakeDamage(playerid, issuerid, Float:amount, weaponid, bodypart);
#endif

/*
OnPlayerGiveDamage(playerid, damagedid, Float:amount, weaponid, bodypart)
*/

public OnPlayerGiveDamage(playerid, damagedid, Float:amount, weaponid, bodypart)
{
if (damagedid != INVALID_PLAYER_ID) {
new
Float:armour,
Float:difference;

GetPlayerArmour(damagedid, armour);

difference = armour - amount;

if (difference > 0.0) {
SetPlayerArmour(damagedid, difference);
} else {
SetPlayerArmour(damagedid, 0.0);
SetPlayerHealth(damagedid, gPlayerHealth[playerid] + difference);
}
}

#if defined CustomHealth_OnPlayerGiveDamage
return CustomHealth_OnPlayerGiveDamage(playerid, damagedid, amount, weaponid, bodypart);
#else
return 1;
#endif
}
#if defined _ALS_OnPlayerGiveDamage
#undef OnPlayerGiveDamage
#else
#define _ALS_OnPlayerGiveDamage
#endif

#define OnPlayerGiveDamage CustomHealth_OnPlayerGiveDamage
#if defined CustomHealth_OnPlayerGiveDamage
forward CustomHealth_OnPlayerGiveDamage(playerid, damagedid, Float:amount, weaponid, bodypart);
#endif

/*
OnPlayerSpawn(playerid)
*/

public OnPlayerSpawn(playerid)
{
SetPlayerTeam(playerid, 0);

#if defined CustomHealth_OnPlayerSpawn
return CustomHealth_OnPlayerSpawn(playerid);
#else
return 1;
#endif
}
#if defined _ALS_OnPlayerSpawn
#undef OnPlayerSpawn
#else
#define _ALS_OnPlayerSpawn
#endif

#define OnPlayerSpawn CustomHealth_OnPlayerSpawn
#if defined CustomHealth_OnPlayerSpawn
forward CustomHealth_OnPlayerSpawn(playerid);
#endif

Но в идеале нужно ещё реализовать собственную team систему.

P.S. Код не тестировал и не компилировал.

Если что. Я это делаю для DM

ziggi
03.07.2016, 20:11
Если что. Я это делаю для DM

И что? Это для всего подходит.

Nexius_Tailer
03.07.2016, 20:30
В общем, вот скрипт:
Такая система дамага ненадёжная и лучше её не ставить. Ещё пару лет назад везде писали, что реализовав систему урона в OnPlayerGiveDamage читеры могут массово убивать игроков (фейково вызывая OnPlayerGiveDamage). Также даже без читов это имеет такой недостаток из-за пинга, как незасчитывание убийства одного игрока другим (killerid в OnPlayerDeath в итоге может быть невалидным).

Если уж и делать наподобие такого, то через OnPlayerWeaponShot.

ziggi
03.07.2016, 20:45
Такая система дамага ненадёжная и лучше её не ставить. Ещё пару лет назад везде писали, что реализовав систему урона в OnPlayerGiveDamage читеры могут массово убивать игроков (фейково вызывая OnPlayerGiveDamage). Также даже без читов это имеет такой недостаток из-за пинга, как незасчитывание убийства одного игрока другим (killerid в OnPlayerDeath в итоге может быть невалидным).

Если уж и делать наподобие такого, то через OnPlayerWeaponShot.

Да, такое возможно. Но фейково можно и OnPlayerWeaponShot вызывать, от этого никуда не деться. В идеале, конечно, нужно связать данные из OnPlayerGiveDamage и OnPlayerTakeDamage. Но если делать всё совсем идеально, то нужно полностью менять систему здоровья, урона и смерти игроков, к счастью, это уже реализовано в weapon-config.inc (http://forum.sa-mp.com/showthread.php?t=563387).

Nexius_Tailer
03.07.2016, 21:10
Да, такое возможно. Но фейково можно и OnPlayerWeaponShot вызывать, от этого никуда не деться. В идеале, конечно, нужно связать данные из OnPlayerGiveDamage и OnPlayerTakeDamage. Но если делать всё совсем идеально, то нужно полностью менять систему здоровья, урона и смерти игроков, к счастью, это уже реализовано в weapon-config.inc (http://forum.sa-mp.com/showthread.php?t=563387).
Кстати, как раз хотел ссылку на него кинуть. Если это то что нужно автору темы - это лучший вариант.