Quellcode durchsuchen

Fixed VIP not ending immediately (#8877)

Added a monitoring to the login-server to notify the map-server, when the VIP status runs out.
Removed VIP status checking from periodic player saving of the map-server.
Added seconds to the output of the `@vip` command.
Added the player name to the output of the `@vip` command.
Fixed a bug where a player would not immediately get the defined gemstone bonus of the VIP group.

Fixes #8873

Thanks to @gidzdlcrz
Lemongrass3110 vor 3 Monaten
Ursprung
Commit
bc645570cb

+ 3 - 3
conf/msg_conf/map_msg.conf

@@ -733,9 +733,9 @@
 701: Invalid time for VIP command.
 702: Time parameter format is +/-<value> to alter. y/a = Year, m = Month, d/j = Day, h = Hour, n/mn = Minute, s = Second.
 703: GM has removed your VIP time.
-704: Player is no longer VIP.
-705: Your VIP status is valid for %d years, %d months, %d days, %d hours and %d minutes.
-706: Player '%s' is now VIP for %d years, %d months, %d days, %d hours and %d minutes.
+704: Player '%s' is no longer VIP.
+705: Your VIP status is valid for %d years, %d months, %d days, %d hours, %d minutes and %d seconds.
+706: Player '%s' is now VIP for %d years, %d months, %d days, %d hours, %d minutes and %d seconds.
 707: You are VIP until: %s
 708: The player is now VIP until: %s
 

+ 3 - 3
conf/msg_conf/map_msg_idn.conf

@@ -726,9 +726,9 @@
 701: Waktu yang dimasukkan salah.
 702: Format waktu yang digunakan +/-<nilai> untuk mengubah. y/a = Tahun, m = Bulan, d/j = Hari, h = Jam, n/mn = Menit, s = Detik.
 703: GM telah menghilangkan waktu VIP anda.
-704: Pemain sudah tidak VIP.
-705: Status VIP anda berlaku dalam %d tahun, %d bulan, %d hari, %d jam dan %d menit.
-706: Pemain '%s' saat ini VIP untuk %d tahun, %d bulan, %d hari, %d jam dan %d menit.
+704: Pemain '%s' sudah tidak VIP.
+705: Status VIP anda berlaku dalam %d tahun, %d bulan, %d hari, %d jam, %d menit dan %d detik.
+706: Pemain '%s' saat ini VIP untuk %d tahun, %d bulan, %d hari, %d jam, %d menit dan %d detik.
 707: VIP anda berlaku hingga: %s
 708: Status VIP pemain aktif hingga: %s
 

+ 3 - 3
conf/msg_conf/map_msg_por.conf

@@ -738,9 +738,9 @@
 701: Tempo inválido para o comando VIP.
 702: O formato do parâmetro de tempo é +/- <valor> para alterar. y/a = Ano, m = Mês, d/j = Dia, h = Hora, n/mn = Minuto, s = Segundo.
 703: GM removeu seu tempo VIP.
-704: O jogador não é mais VIP.
-705: Seu status VIP é válido para %d anos, %d meses, %d dias, %d horas e %d minutos.
-706: O jogador '% s' agora é VIP por %d anos, %d meses, %d dias, %d horas e %d minutos.
+704: O jogador '%s' não é mais VIP.
+705: Seu status VIP é válido para %d anos, %d meses, %d dias, %d horas, %d minutos e %d segundos.
+706: O jogador '% s' agora é VIP por %d anos, %d meses, %d dias, %d horas, %d minutos e %d segundos.
 707: Você é VIP até: %s
 708: O jogador agora é VIP até: %s
 

+ 3 - 3
conf/msg_conf/map_msg_spn.conf

@@ -733,9 +733,9 @@
 701: El tiempo que has introducido no es válido.
 702: El formato del tiempo es +/-<valor>. y/a = Año, m = Mes, d/j = Día, h = Horas, n/mn = Minutos, s = Segundos.
 703: Un GM te ha retirado el VIP.
-704: El jugador ya no es VIP.
-705: Tiempo restante como VIP: Años: %d. Meses: %d. Días: %d. Horas: %d. Minutos: %d.
-706: El jugador '%s' será VIP durante: Años: %d. Meses: %d. Días: %d. Horas: %d. Minutos: %d.
+704: El jugador '%s' ya no es VIP.
+705: Tiempo restante como VIP: Años: %d. Meses: %d. Días: %d. Horas: %d. Minutos: %d. Segundos: %d.
+706: El jugador '%s' será VIP durante: Años: %d. Meses: %d. Días: %d. Horas: %d. Minutos: %d. Segundos: %d.
 707: Serás VIP hasta: %s
 708: El jugador será VIP hasta: %s
 

+ 16 - 0
src/char/char_logif.cpp

@@ -662,6 +662,22 @@ int32 chlogif_parse_vipack(int32 fd) {
 		uint32 groupid = RFIFOL(fd,11); //new group id
 		int32 mapfd = RFIFOL(fd,15); //link to mapserv for ack
 		RFIFOSKIP(fd,19);
+
+		// If it was triggered from login-server and not requested from a specific map-server
+		if( mapfd < 0 ){
+			std::shared_ptr<struct online_char_data> character = util::umap_find( char_get_onlinedb(), aid );
+
+			if( character == nullptr ){
+				return 1;
+			}
+
+			if( character->server < 0 ){
+				return 1;
+			}
+
+			mapfd = map_server[character->server].fd;
+		}
+
 		chmapif_vipack(mapfd,aid,vip_time,groupid,flag);
 	}
 #endif

+ 1 - 1
src/common/socket.hpp

@@ -154,7 +154,7 @@ void set_defaultparse(ParseFunc defaultparse);
 
 /// Server operation request
 enum chrif_req_op {
-	// Char-server <-> login-server oepration
+	// Char-server <-> login-server operation
 	CHRIF_OP_LOGIN_BLOCK = 1,
 	CHRIF_OP_LOGIN_BAN,
 	CHRIF_OP_LOGIN_UNBLOCK,

+ 90 - 0
src/login/account.cpp

@@ -15,6 +15,7 @@
 #include <common/strlib.hpp>
 
 #include "login.hpp" // login_config
+#include "loginchrif.hpp"
 
 /// global defines
 
@@ -60,6 +61,12 @@ static bool account_db_sql_load_str(AccountDB* self, struct mmo_account* acc, co
 static AccountDBIterator* account_db_sql_iterator(AccountDB* self);
 static void account_db_sql_iter_destroy(AccountDBIterator* self);
 static bool account_db_sql_iter_next(AccountDBIterator* self, struct mmo_account* acc);
+TIMER_FUNC(account_disable_webtoken_timer);
+#ifdef VIP_ENABLE
+TIMER_FUNC(account_vip_timeout_timer);
+bool account_db_sql_enable_monitor_vip( AccountDB* self, const uint32 account_id, time_t vip_time );
+bool account_db_sql_disable_monitor_vip( AccountDB* self, const uint32 account_id );
+#endif
 
 static bool mmo_auth_fromsql(AccountDB_SQL* db, struct mmo_account* acc, uint32 account_id);
 static bool mmo_auth_tosql(AccountDB_SQL* db, const struct mmo_account* acc, bool is_new, bool refresh_token);
@@ -83,6 +90,10 @@ AccountDB* account_db_sql(void) {
 	db->vtable.load_num     = &account_db_sql_load_num;
 	db->vtable.load_str     = &account_db_sql_load_str;
 	db->vtable.iterator     = &account_db_sql_iterator;
+#ifdef VIP_ENABLE
+	db->vtable.enable_monitor_vip = &account_db_sql_enable_monitor_vip;
+	db->vtable.disable_monitor_vip = &account_db_sql_disable_monitor_vip;
+#endif
 
 	// initialize to default values
 	db->accounts = nullptr;
@@ -92,6 +103,11 @@ AccountDB* account_db_sql(void) {
 	safestrncpy(db->global_acc_reg_num_table, "global_acc_reg_num", sizeof(db->global_acc_reg_num_table));
 	safestrncpy(db->global_acc_reg_str_table, "global_acc_reg_str", sizeof(db->global_acc_reg_str_table));
 
+	add_timer_func_list( account_disable_webtoken_timer, "account_disable_webtoken_timer" );
+#ifdef VIP_ENABLE
+	add_timer_func_list(account_vip_timeout_timer, "account_vip_timeout_timer");
+#endif
+
 	return &db->vtable;
 }
 
@@ -951,3 +967,77 @@ bool account_db_sql_remove_webtokens( AccountDB* self ){
 
 	return true;
 }
+
+#ifdef VIP_ENABLE
+TIMER_FUNC(account_vip_timeout_timer){
+	struct online_login_data* ld = login_get_online_user( id );
+	AccountDB* db = reinterpret_cast<AccountDB*>( data );
+
+	// Player is not online anymore
+	if( ld == nullptr ){
+		return 0;
+	}
+
+	ld->vip_timeout_tid = INVALID_TIMER;
+
+	struct mmo_account acc;
+
+	if( db->load_num( db, &acc, id ) ){
+		time_t now = time( nullptr );
+		time_t vip_time = acc.vip_time;
+		bool isvip;
+
+		// Is still VIP
+		if( now < vip_time ){
+			t_tick remaining = vip_time - now;
+
+			ld->vip_timeout_tid = add_timer( gettick() + remaining * 1000, account_vip_timeout_timer, id, data );
+
+			isvip = true;
+		}else{
+			isvip = false;
+		}
+
+		logchrif_sendvipdata( ch_server[ld->char_server].fd, &acc, isvip ? 0x1 : 0x0, -1 );
+	}
+
+	return 0;
+}
+
+bool account_db_sql_enable_monitor_vip( AccountDB* self, const uint32 account_id, time_t vip_time ){
+	struct online_login_data* ld = login_get_online_user( account_id );
+
+	if( ld == nullptr ){
+		return false;
+	}
+
+	if( ld->vip_timeout_tid != INVALID_TIMER ){
+		delete_timer( ld->vip_timeout_tid, account_vip_timeout_timer );
+		ld->vip_timeout_tid = INVALID_TIMER;
+	}
+
+	time_t now = time(nullptr);
+	t_tick remaining = vip_time - now;
+
+	ld->vip_timeout_tid = add_timer( gettick() + remaining * 1000, account_vip_timeout_timer, account_id, reinterpret_cast<intptr_t>( self ) );
+
+	return true;
+}
+
+bool account_db_sql_disable_monitor_vip( AccountDB* self, const uint32 account_id ){
+	AccountDB_SQL* db = (AccountDB_SQL*)self;
+
+	struct online_login_data* ld = login_get_online_user( account_id );
+
+	if( ld == nullptr ){
+		return false;
+	}
+
+	if( ld->vip_timeout_tid != INVALID_TIMER ){
+		delete_timer( ld->vip_timeout_tid, account_vip_timeout_timer );
+		ld->vip_timeout_tid = INVALID_TIMER;
+	}
+
+	return true;
+}
+#endif

+ 6 - 0
src/login/account.hpp

@@ -111,6 +111,12 @@ struct AccountDB {
 	/// Removes the web auth token for all accounts
 	bool (*remove_webtokens)(AccountDB* self);
 
+#ifdef VIP_ENABLE
+	bool (*enable_monitor_vip)( AccountDB* self, const uint32 account_id, time_t vip_time );
+
+	bool (*disable_monitor_vip)( AccountDB* self, const uint32 account_id );
+#endif
+
 	/// Modifies the data of an existing account.
 	/// Uses acc->account_id to identify the account.
 	///

+ 3 - 0
src/login/login.cpp

@@ -90,6 +90,9 @@ struct online_login_data* login_add_online_user(int32 char_server, uint32 accoun
 		p->account_id = account_id;
 		p->char_server = char_server;
 		p->waiting_disconnect = INVALID_TIMER;
+#ifdef VIP_ENABLE
+		p->vip_timeout_tid = INVALID_TIMER;
+#endif
 	}else{
 		p->char_server = char_server;
 

+ 3 - 0
src/login/login.hpp

@@ -143,6 +143,9 @@ struct online_login_data {
 	uint32 account_id;
 	int32 waiting_disconnect;
 	int32 char_server;
+#ifdef VIP_ENABLE
+	int32 vip_timeout_tid;
+#endif
 };
 
 /// Auth database

+ 6 - 0
src/login/loginchrif.cpp

@@ -706,6 +706,12 @@ int32 logchrif_parse_reqvipdata(int32 fd) {
 			accounts->save(accounts,&acc, false);
 			if( flag&1 )
 				logchrif_sendvipdata(fd,&acc,((isvip)?0x1:0)|((flag&0x8)?0x4:0),mapfd);
+
+			if( isvip ){
+				accounts->enable_monitor_vip( accounts, aid, vip_time );
+			}else{
+				accounts->disable_monitor_vip( accounts, aid );
+			}
 		}
 	}
 #endif

+ 4 - 0
src/login/loginchrif.hpp

@@ -6,6 +6,8 @@
 
 #include <common/cbasetypes.hpp>
 
+struct mmo_account;
+
 /**
  * Entry point from char-server to log-server.
  * Function that checks incoming command, then splits it to the correct handler.
@@ -23,6 +25,8 @@ int32 logchrif_parse(int32 fd);
  */
 int32 logchrif_sendallwos(int32 sfd, uint8* buf, size_t len);
 
+int32 logchrif_sendvipdata( int32 fd, struct mmo_account* acc, unsigned char flag, int32 mapfd );
+
 /**
  * loginchrif constructor
  *  Initialisation, function called at start of the login-serv.

+ 17 - 7
src/map/atcommand.cpp

@@ -10521,30 +10521,40 @@ ACMD_FUNC(vip) {
 	}
 
 	if (pc_get_group_level(pl_sd) > pc_get_group_level(sd)) {
-		clif_displaymessage(fd, msg_txt(sd,81)); // Your GM level don't authorise you to do this action on this player.
+		clif_displaymessage(fd, msg_txt(sd,81)); // Your GM level doesn't authorize you to perform this action on the specified player.
+		return -1;
+	}
+
+	if( pc_get_group_level( pl_sd ) > 0 ){
+		clif_displaymessage( sd->fd, msg_txt( sd, 437 ) ); // GM's cannot become a VIP.
 		return -1;
 	}
+
 	if(pl_sd->vip.time==0) pl_sd->vip.time=now;
 	pl_sd->vip.time += vipdifftime; //increase or reduce VIP duration
 	
 	if (pl_sd->vip.time <= now) {
 		clif_displaymessage(pl_sd->fd, msg_txt(pl_sd,703)); // GM has removed your VIP time.
-		clif_displaymessage(fd, msg_txt(sd,704)); // Player is no longer VIP.
+
+		if( pl_sd != sd ){
+			sprintf( atcmd_output, msg_txt( sd, 704 ), pl_sd->status.name ); // Player '%s' is no longer VIP.
+			clif_displaymessage( fd, atcmd_output );
+		}
 	} else {
 		int32 year,month,day,hour,minute,second;
 		char timestr[21];
 		
 		split_time((int32)(pl_sd->vip.time-now),&year,&month,&day,&hour,&minute,&second);
-		sprintf(atcmd_output,msg_txt(pl_sd,705),year,month,day,hour,minute); // Your VIP status is valid for %d years, %d months, %d days, %d hours and %d minutes.
+		sprintf(atcmd_output,msg_txt(pl_sd,705),year,month,day,hour,minute,second); // Your VIP status is valid for %d years, %d months, %d days, %d hours, %d minutes and %d seconds.
 		clif_displaymessage(pl_sd->fd,atcmd_output);
-		timestamp2string(timestr,20,pl_sd->vip.time,"%Y-%m-%d %H:%M");
-		sprintf(atcmd_output,msg_txt(pl_sd,707),timestr); // You are VIP until : %s
+		timestamp2string(timestr,20,pl_sd->vip.time,"%Y-%m-%d %H:%M:%S");
+		sprintf(atcmd_output,msg_txt(pl_sd,707),timestr); // You are VIP until: %s
 		clif_displaymessage(pl_sd->fd,atcmd_output);
 
 		if (pl_sd != sd) {
-			sprintf(atcmd_output,msg_txt(sd,706),pl_sd->status.name,year,month,day,hour,minute); // Player '%s' is now VIP for %d years, %d months, %d days, %d hours and %d minutes.
+			sprintf(atcmd_output,msg_txt(sd,706),pl_sd->status.name,year,month,day,hour,minute,second); // Player '%s' is now VIP for %d years, %d months, %d days, %d hours, %d minutes and %d seconds.
 			clif_displaymessage(fd,atcmd_output);
-			sprintf(atcmd_output,msg_txt(sd,708),timestr); // The player is now VIP until : %s
+			sprintf(atcmd_output,msg_txt(sd,708),timestr); // The player is now VIP until: %s
 			clif_displaymessage(fd,atcmd_output);
 		}
 	}

+ 4 - 5
src/map/chrif.cpp

@@ -1556,7 +1556,7 @@ void chrif_parse_ack_vipActive(int32 fd) {
 	uint32 vip_time = RFIFOL(fd,6);
 	uint32 groupid = RFIFOL(fd,10);
 	uint8 flag = RFIFOB(fd,14);
-	TBL_PC *sd = map_id2sd(aid);
+	map_session_data* sd = map_id2sd(aid);
 	bool changed = false;
 
 	if(sd == nullptr) return;
@@ -1564,9 +1564,7 @@ void chrif_parse_ack_vipActive(int32 fd) {
 	sd->group_id = groupid;
 	pc_group_pc_load(sd);
 
-	if ((flag&0x2)) //isgm
-		clif_displaymessage(sd->fd,msg_txt(sd,437));
-	else {
+	if (!(flag&0x2)){ //isgm
 		changed = (sd->vip.enabled != (flag&0x1));
 		if((flag&0x1)) { //isvip
 			sd->vip.enabled = 1;
@@ -1577,12 +1575,13 @@ void chrif_parse_ack_vipActive(int32 fd) {
 				ShowError("intif_parse_ack_vipActive: Storage size for player %s (%d:%d) is larger than MAX_STORAGE. Storage size has been set to MAX_STORAGE.\n", sd->status.name, sd->status.account_id, sd->status.char_id);
 				sd->storage.max_amount = MAX_STORAGE;
 			}
+			sd->special_state.no_gemstone = battle_config.vip_gemstone;
 		} else if (sd->vip.enabled) {
 			sd->vip.enabled = 0;
 			sd->vip.time = 0;
 			sd->storage.max_amount = MIN_STORAGE;
 			sd->special_state.no_gemstone = 0;
-			clif_displaymessage(sd->fd,msg_txt(sd,438));
+			clif_displaymessage(sd->fd,msg_txt(sd,438)); // You are no longer VIP.
 		}
 	}
 	// Show info if status changed

+ 1 - 2
src/map/pc.cpp

@@ -12885,8 +12885,7 @@ static TIMER_FUNC(pc_autosave){
 		//Save char.
 		last_save_id = sd->bl.id;
 		save_flag = 2;
-		if (pc_isvip(sd)) // Check if we're still VIP
-			chrif_req_login_operation(1, sd->status.name, CHRIF_OP_LOGIN_VIP, 0, 1, 0);
+
 		chrif_save(sd, CSAVE_INVENTORY|CSAVE_CART);
 		break;
 	}