Просмотр полной версии : [Вопрос] Проблема с GetPlayerHealth
Почему 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"
А если вот так попробовать?
new
Float:health;
GetPlayerHealth(playerid, health);
printf("{HP: %.0f, %.0f},", pInfo[playerid][pHealth], health);
Фича такая: за 255 значением следует "количество хп - 256"
Неверно перевели.
Все значения которые идут после 255 корректируются как (не дословный перевод, но понятный):
256 -> 0
257 -> 1
258 -> 2
Есть выход с ситуации?
Перехват 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);
Со скобками ж просто выведет, толку то)
Ну 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, тем самым будет выдавать неправильное значение. Наверное всё-же своя система урона или что-то вроде этого - это лучший вариант.
Надёжно, но тогда если где-нибудь сверить хп в переменной и только что узнанное хп, то они не будут совпадать даже будучи реально равными. Если такая проверка где-то будет, то вот пример, как сделать чтобы она работала корректно:
//Где-нибудь
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)
С хп меньше 500 все время выдает 256
Вы совсем не то делаете.
В общем, вот скрипт:
/*
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. Код не тестировал и не компилировал.
Вы совсем не то делаете.
В общем, вот скрипт:
/*
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
Если что. Я это делаю для DM
И что? Это для всего подходит.
Nexius_Tailer
03.07.2016, 20:30
В общем, вот скрипт:
Такая система дамага ненадёжная и лучше её не ставить. Ещё пару лет назад везде писали, что реализовав систему урона в OnPlayerGiveDamage читеры могут массово убивать игроков (фейково вызывая OnPlayerGiveDamage). Также даже без читов это имеет такой недостаток из-за пинга, как незасчитывание убийства одного игрока другим (killerid в OnPlayerDeath в итоге может быть невалидным).
Если уж и делать наподобие такого, то через OnPlayerWeaponShot.
Такая система дамага ненадёжная и лучше её не ставить. Ещё пару лет назад везде писали, что реализовав систему урона в 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).
Кстати, как раз хотел ссылку на него кинуть. Если это то что нужно автору темы - это лучший вариант.
Powered by vBulletin® Version 4.2.0 Copyright © 2024 vBulletin Solutions, Inc. All rights reserved. Перевод: zCarot