Issue information

Issue ID
#3983
Status
Fixed
Severity
Low
Started
Hercules Elf Bot
Dec 29, 2009 20:49
Last Post
Hercules Elf Bot
Dec 29, 2009 20:49
Confirmation
N/A

Hercules Elf Bot - Dec 29, 2009 20:49

Originally posted by [b]Paradox924X[/b]
http://www.eathena.ws/board/index.php?autocom=bugtracker&showbug=3983

common/mmo.h:
CODE
struct guild_member {
    int account_id, char_id;
    short hair,hair_color,gender,class_,lv;
    unsigned int exp;
    int exp_payper;
    short online,position;
    char name[NAME_LENGTH];
    struct map_session_data *sd;
    unsigned char modified;
};


The server defines the guild_member struct's exp variable as an unsigned integer, but the client stores this value in a signed integer, thus causing overflow in the client when the value exceeds INT_MAX (2^31-1).
The server caps the value for devotion to UINT_MAX (2^32-1) in the functions guild_payexp(), guild_getexp(), and guild_payexp_timer_sub() all with similar code:
CODE
...
    if (c->exp > UINT_MAX - exp)
        c->exp = UINT_MAX;
    else
        c->exp += exp;
...


Way back in r7103, exp was changed from a signed integer to an unsigned integer, thus making this issue more apparent.
I assume this change was made to allow storage of higher values and the client's accepted maximum value was disregarded.

The major problem here lies beyond the visual confusion found in-game, in the fact that the guild will no longer gain exp from a taxed individual who has hit his or her exp devotion cap of UINT_MAX.
This is because exp isn't applied to the guild immediately when a taxed guild member gains exp, but rather every 10 seconds (by default as per GUILD_PAYEXP_INVERVAL defined in map/guild.c) and prior to that, the exp is stored in a DBMap of char_id->struct guild_expcache* represented as guild_expcache_db.
CODE
struct guild_expcache {
    int guild_id, account_id, char_id;
    unsigned int exp;
};


Because of the fact that this expcache is a DBMap per-character and has a maximum of UINT_MAX for the 'exp' variable, when a player reaches that maximum value, the code previously mentioned prevents it from being increased further, so when the GUILD_PAYEXP_INVERVAL passes and the timer triggers an update of the exp, it will not notice any gain.

There are two things that should be done:
1) Increase the storage space (hold values in uint64?)
2) Cap the value to INT_MAX before sending it to the client to prevent confusion (Currently shows -1 when player has reached an exp devotion value of UINT_MAX).

These two changes will mask the pitfalls of using a DBMap and a timer to delay the increase of guild exp rather than to simply delay the notification to players of a guild exp increase.

This post has been edited by Paradox924X: Dec 29 2009, 10:43 PM