Skip to content

Commit

Permalink
Merge pull request #3141 from guilherme-gm/fix-instance-destroy
Browse files Browse the repository at this point in the history
Fixes on instance information/destruction
  • Loading branch information
MishimaHaruna authored Jun 2, 2022
2 parents a7ee823 + 37bca6a commit 9ae6ddb
Show file tree
Hide file tree
Showing 7 changed files with 131 additions and 59 deletions.
57 changes: 29 additions & 28 deletions src/map/clif.c
Original file line number Diff line number Diff line change
Expand Up @@ -11504,7 +11504,8 @@ static void clif_parse_LoadEndAck(int fd, struct map_session_data *sd)
if (first_time) {
int i;

ARR_FIND(0, instance->instances, i, instance->list[i].owner_type == IOT_CHAR && instance->list[i].owner_id == sd->status.account_id);
ARR_FIND(0, instance->instances, i, instance_is_active(instance->list[i])
&& instance->list[i].owner_type == IOT_CHAR && instance->list[i].owner_id == sd->status.account_id);

if (i < instance->instances) {
sd->instances = 1;
Expand Down Expand Up @@ -19504,13 +19505,13 @@ static void clif_font(struct map_session_data *sd)
/*==========================================
* Instancing Window
*------------------------------------------*/
static int clif_instance(int instance_id, int type, int flag)
static int clif_instance(int instance_id, enum instance_window_info_type type, int flag)
{
struct map_session_data *sd = NULL;
unsigned char buf[255];
enum send_target target = PARTY;

switch( instance->list[instance_id].owner_type ) {
switch (instance->list[instance_id].owner_type) {
case IOT_NONE:
return 0;
case IOT_GUILD:
Expand All @@ -19529,52 +19530,52 @@ static int clif_instance(int instance_id, int type, int flag)
break;
}

if( !sd )
if (!sd)
return 0;

switch( type ) {
case 1:
switch (type) {
case INSTANCE_WND_INFO_CREATE:
// S 0x2cb <Instance name>.61B <Standby Position>.W
// Required to start the instancing information window on Client
// This window re-appear each "refresh" of client automatically until type 4 is send to client.
WBUFW(buf,0) = 0x02CB;
memcpy(WBUFP(buf,2),instance->list[instance_id].name,INSTANCE_NAME_LENGTH);
WBUFW(buf,63) = flag;
clif->send(buf,packet_len(0x02CB),&sd->bl,target);
WBUFW(buf, 0) = 0x02CB;
memcpy(WBUFP(buf, 2), instance->list[instance_id].name, INSTANCE_NAME_LENGTH);
WBUFW(buf, 63) = flag;
clif->send(buf, packet_len(0x02CB), &sd->bl, target);
break;
case 2:
case INSTANCE_WND_INFO_QUEUE_POS:
// S 0x2cc <Standby Position>.W
// To announce Instancing queue creation if no maps available
// flag is priority, negative value mean cancel reservation
WBUFW(buf,0) = 0x02CC;
WBUFW(buf,2) = flag;
clif->send(buf,packet_len(0x02CC),&sd->bl,target);
WBUFW(buf, 0) = 0x02CC;
WBUFW(buf, 2) = flag;
clif->send(buf, packet_len(0x02CC), &sd->bl, target);
break;
case 3:
case 4:
case INSTANCE_WND_INFO_PROGRESS_TIME:
case INSTANCE_WND_INFO_IDLE_TIME:
// S 0x2cd <Instance Name>.61B <Instance Remaining Time>.L <Instance Noplayers close time>.L
WBUFW(buf,0) = 0x02CD;
memcpy(WBUFP(buf,2),instance->list[instance_id].name,61);
if( type == 3 ) {
WBUFL(buf,63) = instance->list[instance_id].progress_timeout;
WBUFL(buf,67) = 0;
WBUFW(buf, 0) = 0x02CD;
memcpy(WBUFP(buf, 2), instance->list[instance_id].name, 61);
if (type == INSTANCE_WND_INFO_PROGRESS_TIME) {
WBUFL(buf, 63) = instance->list[instance_id].progress_timeout;
WBUFL(buf, 67) = 0;
} else {
WBUFL(buf,63) = 0;
WBUFL(buf,67) = instance->list[instance_id].idle_timeout;
WBUFL(buf, 63) = 0;
WBUFL(buf, 67) = instance->list[instance_id].idle_timeout;
}
clif->send(buf,packet_len(0x02CD),&sd->bl,target);
clif->send(buf, packet_len(0x02CD), &sd->bl, target);
break;
case 5:
case INSTANCE_WND_INFO_DESTROY:
// S 0x2ce <Message ID>.L
// 0 = Notification (EnterLimitDate update?)
// 1 = The Memorial Dungeon expired; it has been destroyed
// 2 = The Memorial Dungeon's entry time limit expired; it has been destroyed
// 3 = The Memorial Dungeon has been removed.
// 4 = Create failure (removes the instance window)
WBUFW(buf,0) = 0x02CE;
WBUFL(buf,2) = flag;
WBUFW(buf, 0) = 0x02CE;
WBUFL(buf, 2) = flag;
//WBUFL(buf,6) = EnterLimitDate;
clif->send(buf,packet_len(0x02CE),&sd->bl,target);
clif->send(buf, packet_len(0x02CE), &sd->bl, target);
break;
}
return 0;
Expand Down
29 changes: 28 additions & 1 deletion src/map/clif.h
Original file line number Diff line number Diff line change
Expand Up @@ -874,6 +874,33 @@ enum ITEM_OBTAIN_TYPE {
ITEM_OBTAIN_TYPE_NPC_ITEM = 2,
};

/**
* Instance information window update types.
*/
enum instance_window_info_type {
/**
* Informs about instance creation
*/
INSTANCE_WND_INFO_CREATE = 1,
/**
* Informs an update in instance queue position
*/
INSTANCE_WND_INFO_QUEUE_POS = 2,
/**
* Informs the instance is in progress (has players on it) and when it will timeout
*/
INSTANCE_WND_INFO_PROGRESS_TIME = 3,
/**
* Informs the instance is idle (no players on it) and when it will timeout
*/
INSTANCE_WND_INFO_IDLE_TIME = 4,
/**
* Informs the instance was destroyed.
* @see instance_destroy_reason for reason flag values.
*/
INSTANCE_WND_INFO_DESTROY = 5,
};

/**
* Clif.c Interface
**/
Expand Down Expand Up @@ -1328,7 +1355,7 @@ struct clif_interface {
void (*sendbgemblem_area) (struct map_session_data *sd);
void (*sendbgemblem_single) (int fd, struct map_session_data *sd);
/* instance-related */
int (*instance) (int instance_id, int type, int flag);
int (*instance) (int instance_id, enum instance_window_info_type type, int flag);
void (*instance_join) (int fd, int instance_id);
void (*instance_leave) (int fd);
/* pet-related */
Expand Down
59 changes: 35 additions & 24 deletions src/map/instance.c
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ static bool instance_is_valid(int instance_id)
return false;
}

if( instance->list[instance_id].state == INSTANCE_FREE ) {// uninitialized/freed instance slot
if (!instance_is_active(instance->list[instance_id])) { // uninitialized/freed/being freed instance slot
return false;
}

Expand Down Expand Up @@ -170,7 +170,7 @@ static int instance_create(int owner_id, const char *name, enum instance_owner_t
}
}

clif->instance(i, 1, 0); // Start instancing window
clif->instance(i, INSTANCE_WND_INFO_CREATE, 0); // Start instancing window
return i;
}

Expand All @@ -190,7 +190,7 @@ static int instance_create(int owner_id, const char *name, enum instance_owner_t
static int instance_add_map(const char *name, int instance_id, bool usebasename, const char *map_name)
{
int16 m = map->mapname2mapid(name);
int i, im = -1;
int i, im = MAPID_NONE;
size_t num_cell, size, j;

nullpo_retr(-1, name);
Expand Down Expand Up @@ -543,6 +543,7 @@ static void instance_del_map(int16 m)

map->removemapdb(&map->list[m]);
memset(&map->list[m], 0x00, sizeof(map->list[0]));
map->list[m].m = MAPID_NONE; // Marks this map as unallocated so server doesn't try to clean it up later on.
map->list[m].name[0] = 0;
map->list[m].instance_id = -1;
map->list[m].mob_delete_timer = INVALID_TIMER;
Expand All @@ -567,20 +568,19 @@ static void instance_destroy(int instance_id)
struct party_data *p = NULL;
struct guild *g = NULL;
short *iptr = NULL;
int type;
unsigned int now = (unsigned int)time(NULL);

if( !instance->valid(instance_id) )
return; // nothing to do

if( instance->list[instance_id].progress_timeout && instance->list[instance_id].progress_timeout <= now )
type = 1;
else if( instance->list[instance_id].idle_timeout && instance->list[instance_id].idle_timeout <= now )
type = 2;
else
type = 3;
enum instance_destroy_reason type = INSTANCE_DESTROY_OTHER;
bool idle = (instance->list[instance_id].users == 0);
if (!idle && instance->list[instance_id].progress_timeout && instance->list[instance_id].progress_timeout <= now)
type = INSTANCE_DESTROY_PROG_TIMEOUT;
else if (idle && instance->list[instance_id].idle_timeout && instance->list[instance_id].idle_timeout <= now)
type = INSTANCE_DESTROY_IDLE_TIMEOUT;

clif->instance(instance_id, 5, type); // Report users this instance has been destroyed
clif->instance(instance_id, INSTANCE_WND_INFO_DESTROY, type); // Report users this instance has been destroyed

switch ( instance->list[instance_id].owner_type ) {
case IOT_NONE:
Expand Down Expand Up @@ -619,6 +619,9 @@ static void instance_destroy(int instance_id)
iptr[i] = -1;
}

// mark it as being destroyed so server doesn't try to give players more information about it
instance->list[instance_id].state = INSTANCE_DESTROYING;

if (instance->list[instance_id].map) {
int last = 0;
while (instance->list[instance_id].num_map && last != instance->list[instance_id].map[0]) {
Expand All @@ -643,36 +646,41 @@ static void instance_destroy(int instance_id)
if( instance->list[instance_id].map )
aFree(instance->list[instance_id].map);

HPM->data_store_destroy(&instance->list[instance_id].hdata);

// Clean up remains of the old instance and mark it as available for a new one
memset(&instance->list[instance_id], 0x0, sizeof(instance->list[0]));
instance->list[instance_id].map = NULL;
instance->list[instance_id].state = INSTANCE_FREE;
instance->list[instance_id].num_map = 0;

HPM->data_store_destroy(&instance->list[instance_id].hdata);
}

/*--------------------------------------
* Checks if there are users in the instance or not to start idle timer
*--------------------------------------*/
static void instance_check_idle(int instance_id)
{
bool idle = true;
unsigned int now = (unsigned int)time(NULL);

if( !instance->valid(instance_id) || instance->list[instance_id].idle_timeoutval == 0 )
if (!instance->valid(instance_id) || instance->list[instance_id].idle_timeoutval == 0)
return;

if( instance->list[instance_id].users )
bool idle = true;
if (instance->list[instance_id].users)
idle = false;

if( instance->list[instance_id].idle_timer != INVALID_TIMER && !idle ) {
if (instance->list[instance_id].idle_timer != INVALID_TIMER && !idle) {
timer->delete(instance->list[instance_id].idle_timer, instance->destroy_timer);
instance->list[instance_id].idle_timer = INVALID_TIMER;
instance->list[instance_id].idle_timeout = 0;
clif->instance(instance_id, 3, 0); // Notify instance users normal instance expiration
} else if( instance->list[instance_id].idle_timer == INVALID_TIMER && idle ) {

// Notify instance users normal instance expiration
clif->instance(instance_id, INSTANCE_WND_INFO_PROGRESS_TIME, 0);
} else if (instance->list[instance_id].idle_timer == INVALID_TIMER && idle) {
unsigned int now = (unsigned int) time(NULL);
int64 destroy_tick = timer->gettick() + instance->list[instance_id].idle_timeoutval * 1000;
instance->list[instance_id].idle_timeout = now + instance->list[instance_id].idle_timeoutval;
instance->list[instance_id].idle_timer = timer->add( timer->gettick() + instance->list[instance_id].idle_timeoutval * 1000, instance->destroy_timer, instance_id, 0);
clif->instance(instance_id, 4, 0); // Notify instance users it will be destroyed of no user join it again in "X" time
instance->list[instance_id].idle_timer = timer->add(destroy_tick, instance->destroy_timer, instance_id, 0);

// Notify instance users it will be destroyed if no user join it again in "X" time
clif->instance(instance_id, INSTANCE_WND_INFO_IDLE_TIME, 0);
}
}

Expand Down Expand Up @@ -822,6 +830,9 @@ static void do_reload_instance(void)
int i, k;

for(i = 0; i < instance->instances; i++) {
if (!instance_is_valid(i))
continue; // don't try to restart an invalid instance

for(k = 0; k < instance->list[i].num_map; k++) {
if( !map->list[map->list[instance->list[i].map[k]].instance_src_map].flag.src4instance )
break;
Expand Down
30 changes: 29 additions & 1 deletion src/map/instance.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,19 @@ struct map_session_data;

#define INSTANCE_NAME_LENGTH (60+1)

/**
* true if instance is in an active/playable state.
* In other words, if a player can interact with it.
*
* @param inst instance_data to be checked
*/
#define instance_is_active(inst) ((inst).state == INSTANCE_IDLE || (inst).state == INSTANCE_BUSY)

typedef enum instance_state {
INSTANCE_FREE,
INSTANCE_IDLE,
INSTANCE_BUSY
INSTANCE_BUSY,
INSTANCE_DESTROYING,
} instance_state;

enum instance_owner_type {
Expand All @@ -46,6 +55,25 @@ enum instance_owner_type {
IOT_MAX,
};

/**
* Reason for instance being destroyed.
* Note: These numbers are client-dependent.
*/
enum instance_destroy_reason {
/**
* Time to progress in the instance has expired.
*/
INSTANCE_DESTROY_PROG_TIMEOUT = 1,
/**
* The instance has been empty for too long.
*/
INSTANCE_DESTROY_IDLE_TIMEOUT = 2,
/**
* Other reason
*/
INSTANCE_DESTROY_OTHER = 3,
};

struct instance_data {
unsigned short id;
char name[INSTANCE_NAME_LENGTH]; ///< Instance Name - required for clif functions.
Expand Down
5 changes: 5 additions & 0 deletions src/map/map.h
Original file line number Diff line number Diff line change
Expand Up @@ -958,6 +958,11 @@ struct map_drop_list {
int drop_per;
};

/**
* Map ID (m) for "none" or unallocated map.
*/
#define MAPID_NONE -1

struct map_data {
char name[MAP_NAME_LENGTH];
uint16 index; // The map index used by the mapindex* functions.
Expand Down
4 changes: 2 additions & 2 deletions src/plugins/HPMHooking/HPMHooking.Defs.inc
Original file line number Diff line number Diff line change
Expand Up @@ -1862,8 +1862,8 @@ typedef void (*HPMHOOK_pre_clif_sendbgemblem_area) (struct map_session_data **sd
typedef void (*HPMHOOK_post_clif_sendbgemblem_area) (struct map_session_data *sd);
typedef void (*HPMHOOK_pre_clif_sendbgemblem_single) (int *fd, struct map_session_data **sd);
typedef void (*HPMHOOK_post_clif_sendbgemblem_single) (int fd, struct map_session_data *sd);
typedef int (*HPMHOOK_pre_clif_instance) (int *instance_id, int *type, int *flag);
typedef int (*HPMHOOK_post_clif_instance) (int retVal___, int instance_id, int type, int flag);
typedef int (*HPMHOOK_pre_clif_instance) (int *instance_id, enum instance_window_info_type *type, int *flag);
typedef int (*HPMHOOK_post_clif_instance) (int retVal___, int instance_id, enum instance_window_info_type type, int flag);
typedef void (*HPMHOOK_pre_clif_instance_join) (int *fd, int *instance_id);
typedef void (*HPMHOOK_post_clif_instance_join) (int fd, int instance_id);
typedef void (*HPMHOOK_pre_clif_instance_leave) (int *fd);
Expand Down
6 changes: 3 additions & 3 deletions src/plugins/HPMHooking/HPMHooking_map.Hooks.inc
Original file line number Diff line number Diff line change
Expand Up @@ -18906,11 +18906,11 @@ void HP_clif_sendbgemblem_single(int fd, struct map_session_data *sd) {
}
return;
}
int HP_clif_instance(int instance_id, int type, int flag) {
int HP_clif_instance(int instance_id, enum instance_window_info_type type, int flag) {
int hIndex = 0;
int retVal___ = 0;
if (HPMHooks.count.HP_clif_instance_pre > 0) {
int (*preHookFunc) (int *instance_id, int *type, int *flag);
int (*preHookFunc) (int *instance_id, enum instance_window_info_type *type, int *flag);
*HPMforce_return = false;
for (hIndex = 0; hIndex < HPMHooks.count.HP_clif_instance_pre; hIndex++) {
preHookFunc = HPMHooks.list.HP_clif_instance_pre[hIndex].func;
Expand All @@ -18925,7 +18925,7 @@ int HP_clif_instance(int instance_id, int type, int flag) {
retVal___ = HPMHooks.source.clif.instance(instance_id, type, flag);
}
if (HPMHooks.count.HP_clif_instance_post > 0) {
int (*postHookFunc) (int retVal___, int instance_id, int type, int flag);
int (*postHookFunc) (int retVal___, int instance_id, enum instance_window_info_type type, int flag);
for (hIndex = 0; hIndex < HPMHooks.count.HP_clif_instance_post; hIndex++) {
postHookFunc = HPMHooks.list.HP_clif_instance_post[hIndex].func;
retVal___ = postHookFunc(retVal___, instance_id, type, flag);
Expand Down

0 comments on commit 9ae6ddb

Please sign in to comment.