src/map/atcommand.c | 145 ++++++++++++++++++++++++++++++++++++++++++++++++++++
src/map/chrif.c | 111 ++++++++++++++++++++++++++++++++++++++++
src/map/chrif.h | 9 ++++
src/map/clif.c | 13 +++++
src/map/pc.c | 5 ++
5 files changed, 283 insertions(+)
diff --git a/src/map/atcommand.c b/src/map/atcommand.c
index b5e8fa7..31f7793 100644
--- a/src/map/atcommand.c
+++ b/src/map/atcommand.c
@@ -9374,6 +9374,149 @@ static inline void atcmd_channel_help(int fd, const char *command, bool can_crea
clif->message(fd,atcmd_output);
return true;
}
+
+ACMD(maintenance) {
+ int group_id, kick_duration, maintenance_duration;
+ char reason[99], esc_reason[198], esc_name[46], min_display[3];
+ short weekday, hour, minute;
+ if ( chrif->maintenance_starttime > time(NULL) ) {
+ char aaa[255];
+ int countdown = chrif->maintenance_starttime - (int)time(NULL);
+ clif->message( fd, "Type '@maintenanceoff' to turn off maintenance mode." );
+ safesnprintf( aaa, 255, "Maintenance mode will start in %d min %d sec.", countdown /60, countdown %60 );
+ clif->message( fd, aaa );
+ return true;
+ }
+ if ( chrif->maintenance_endtime > time(NULL) ) {
+ char aaa[255];
+ int countdown = chrif->maintenance_endtime - (int)time(NULL);
+ clif->message( fd, "Type '@maintenanceoff' to turn off maintenance mode." );
+ safesnprintf( aaa, 255, "Server is currently in maintenance mode, will end in %d min %d sec on %s", countdown /60, countdown %60, chrif->maintenance_timeformat );
+ clif->message( fd, aaa );
+ return true;
+ }
+ if ( !message || !*message ) {
+ clif->message( fd, "@maintenance Syntax :" );
+ clif->message( fd, "@maintenance <Group ID can stay 1~99> <duration to kick in minute> <maintenance duration in minute> <reason>" );
+ return false;
+ }
+ if ( sscanf( message, "%d %d %d %99[^\n]", &group_id, &kick_duration, &maintenance_duration, &reason ) < 4 ) {
+ clif->message( fd, "@maintenance Syntax :" );
+ clif->message( fd, "@maintenance <Group ID can stay 1~99> <duration to kick in minute> <maintenance duration in minute> <reason>" );
+ return false;
+ }
+ if ( !group_id ) {
+ clif->message( fd, "The Group ID field cannot be 0, otherwise normal player able to login." );
+ return false;
+ }
+ if ( group_id < 1 || group_id > 99 ) {
+ safesnprintf( atcmd_output, 99, "Invalid Group ID %d. Range must between 1~99.", group_id );
+ clif->message( fd, atcmd_output );
+ return false;
+ }
+ if ( kick_duration <= 0 ) {
+ clif->message( fd, "Kick duration cannot be 0 or negative numbers." );
+ return false;
+ }
+ if ( kick_duration > 1440 ) {
+ clif->message( fd, "Kick duration cannot be more than 1 day." );
+ return false;
+ }
+ if ( maintenance_duration <= 0 ) {
+ clif->message( fd, "Maintenance duration cannot be 0 or negative numbers." );
+ return false;
+ }
+ if ( maintenance_duration > 10080 ) {
+ clif->message( fd, "Maintenance duration cannot be more than 1 week." );
+ return false;
+ }
+ if ( strlen(reason) < 4 ) {
+ clif->message( fd, "You must input a valid reason for doing this." );
+ return false;
+ }
+ SQL->EscapeString( map->mysql_handle, esc_name, sd->status.name );
+ SQL->EscapeString( map->mysql_handle, esc_reason, reason );
+ if ( SQL->Query( map->mysql_handle, "insert into maintenance values ( null, %d, '%s', '%s', %d, now(), timestampadd( minute, %d, now() ), timestampadd( minute, %d, now() ) )", sd->status.account_id, esc_name, esc_reason, group_id, kick_duration, kick_duration + maintenance_duration ) == SQL_ERROR ) {
+ Sql_ShowDebug( map->mysql_handle );
+ return false;
+ }
+ if ( SQL->Query( map->mysql_handle, "select unix_timestamp( start_time ), unix_timestamp( end_time ), weekday( end_time ), hour( end_time ), minute( end_time ) from maintenance where id = ( select max(id) from maintenance )" ) == SQL_ERROR ) {
+ Sql_ShowDebug( map->mysql_handle );
+ return false;
+ }
+ else if ( SQL->NextRow( map->mysql_handle ) == SQL_SUCCESS ) {
+ char *data;
+ chrif->maintenance_group = group_id;
+ if ( SQL->GetData( map->mysql_handle, 0, &data, NULL ) == SQL_SUCCESS )
+ chrif->maintenance_starttime = atoi(data);
+ if ( SQL->GetData( map->mysql_handle, 1, &data, NULL ) == SQL_SUCCESS )
+ chrif->maintenance_endtime = atoi(data);
+ if ( SQL->GetData( map->mysql_handle, 2, &data, NULL ) == SQL_SUCCESS )
+ weekday = atoi(data);
+ if ( SQL->GetData( map->mysql_handle, 3, &data, NULL ) == SQL_SUCCESS )
+ hour = atoi(data);
+ if ( SQL->GetData( map->mysql_handle, 4, &data, NULL ) == SQL_SUCCESS )
+ minute = atoi(data);
+ SQL->FreeResult( map->mysql_handle );
+ }
+ else {
+ SQL->FreeResult( map->mysql_handle );
+ return false;
+ }
+ { // stupid date_format doesn't work
+ char* weekdayname[7] = { "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday" };
+ char am_pm[3];
+ if ( hour == 0 ) {
+ hour = 12;
+ safesnprintf( am_pm, 3, "AM" );
+ }
+ else if ( hour < 12 )
+ safesnprintf( am_pm, 3, "AM" );
+ else {
+ hour = hour - 12;
+ safesnprintf( am_pm, 3, "PM" );
+ }
+ if ( minute < 10 )
+ safesnprintf( min_display, 3, "0%d", minute );
+ else
+ safesnprintf( min_display, 3, "%d", minute );
+ safesnprintf( chrif->maintenance_timeformat, 24, "%s, %d:%s %s", weekdayname[ weekday ], hour, min_display, am_pm );
+ safesnprintf( atcmd_output, 255, "Maintenance mode will be commence in %d minutes. Players are adviced to log out right now. Maintenance last %d minutes. Server will come back up on %s", kick_duration, maintenance_duration, chrif->maintenance_timeformat );
+ intif->broadcast( atcmd_output , strlen(atcmd_output)+1, 0xFFFF00 );
+ }
+ chrif->maintenance_countid = timer->add( timer->gettick() +( ( kick_duration == 1 )? 1000 : 60000 ), chrif->maintenance_countdown, 0, 0 );
+ ShowStatus( CL_YELLOW "Maintenance will start in %d min by " CL_GREEN "%s" CL_RESET ".\n", kick_duration, sd->status.name );
+ return true;
+}
+
+ACMD(maintenanceoff) {
+ char esc_name[46];
+ if ( chrif->maintenance_endtime <= time(NULL) ) {
+ clif->message( fd, "The server is currently in not in maintenance mode." );
+ return true;
+ }
+ SQL->EscapeString( map->mysql_handle, esc_name, sd->status.name );
+ if ( SQL->Query( map->mysql_handle, "insert into maintenance values ( null, %d, '%s', ' @maintenanceoff', 0, null, now(), now() )", sd->status.account_id, esc_name ) == SQL_ERROR ) {
+ Sql_ShowDebug( map->mysql_handle );
+ return false;
+ }
+ chrif->maintenance_group = 0;
+ chrif->maintenance_starttime = (int)time(NULL);
+ chrif->maintenance_endtime = (int)time(NULL);
+ if ( chrif->maintenance_countid > 0 ) {
+ timer->delete( chrif->maintenance_countid, chrif->maintenance_countdown );
+ chrif->maintenance_countid = 0;
+ }
+ if ( chrif->maintenance_timerid > 0 ) {
+ timer->delete( chrif->maintenance_timerid, chrif->maintenance_duration );
+ chrif->maintenance_timerid = 0;
+ }
+ safesnprintf( atcmd_output, 255, "%s ended the Maintenance mode. Players are able to login now.", sd->status.name );
+ intif->broadcast( atcmd_output , strlen(atcmd_output)+1, 0xFFFF00 );
+ ShowStatus( CL_YELLOW "Maintenance has ended by " CL_GREEN "%s" CL_RESET ".\n", sd->status.name );
+ return true;
+}
+
/**
* Fills the reference of available commands in atcommand DBMap
**/
@@ -9384,6 +9527,8 @@ void atcommand_basecommands(void) {
* Command reference list, place the base of your commands here
**/
AtCommandInfo atcommand_base[] = {
+ ACMD_DEF(maintenance),
+ ACMD_DEF(maintenanceoff),
ACMD_DEF2("warp", mapmove),
ACMD_DEF(where),
ACMD_DEF(jumpto),
diff --git a/src/map/chrif.c b/src/map/chrif.c
index ebdace2..f5e2b78 100644
--- a/src/map/chrif.c
+++ b/src/map/chrif.c
@@ -413,6 +413,63 @@ bool chrif_changemapserverack(int account_id, int login_id1, int login_id2, int
return (!login_id1)?false:true; // Is this the best approach here?
}
+int chrif_maintenance_countdown( int tid, int64 tick, int id, intptr data ) {
+ char aaa[255];
+ int countdown = chrif->maintenance_starttime - (int)time(NULL);
+ if ( countdown > 90 ) {
+ safesnprintf( aaa, 255, "Maintainance will start in %d minutes", countdown /60 );
+ intif->broadcast( aaa , strlen(aaa)+1, 0xFFFF00 );
+ timer->delete( chrif->maintenance_countid, chrif->maintenance_countdown );
+ if ( ( countdown % 60 ) > 0 ) // fine tune the timer
+ chrif->maintenance_countid = timer->add( timer->gettick() + ( ( countdown % 60 ) * 1000 ), chrif->maintenance_countdown, 0, 0 );
+ else
+ chrif->maintenance_countid = timer->add( timer->gettick() + 60000, chrif->maintenance_countdown, 0, 0 );
+ }
+ else if ( countdown > 14 ) {
+ safesnprintf( aaa, 255, "Maintainance will start in %d seconds", countdown );
+ intif->broadcast( aaa , strlen(aaa)+1, 0xFFFF00 );
+ timer->delete( chrif->maintenance_countid, chrif->maintenance_countdown );
+ if ( ( countdown % 5 ) > 0 ) // fine tune the timer
+ chrif->maintenance_countid = timer->add( timer->gettick() + ( ( countdown % 5 ) * 1000 ), chrif->maintenance_countdown, 0, 0 );
+ else
+ chrif->maintenance_countid = timer->add( timer->gettick() + 5000, chrif->maintenance_countdown, 0, 0 );
+ }
+ else if ( countdown > 0 ) {
+ safesnprintf( aaa, 255, "Maintainance will start in %d seconds", countdown );
+ intif->broadcast( aaa , strlen(aaa)+1, 0xFFFF00 );
+ timer->delete( chrif->maintenance_countid, chrif->maintenance_countdown );
+ chrif->maintenance_countid = timer->add( timer->gettick() + 1000, chrif->maintenance_countdown, 0, 0 );
+ }
+ else {
+ struct s_mapiterator* iter = mapit->alloc( MAPIT_NORMAL, BL_PC );
+ TBL_PC *sd;
+ safesnprintf( aaa, 255, "Maintainance starts now. Every player will be kick out." );
+ intif->broadcast( aaa , strlen(aaa)+1, 0xFFFF00 );
+ for ( sd = (TBL_PC*)mapit->first(iter); mapit->exists(iter); sd = (TBL_PC*)mapit->next(iter) )
+ if ( sd->group_id < chrif->maintenance_group )
+ clif->authfail_fd( sd->fd, 1 );
+ mapit->free(iter);
+ timer->delete( chrif->maintenance_countid, chrif->maintenance_countdown );
+ chrif->maintenance_countid = 0;
+ chrif->maintenance_timerid = timer->add( timer->gettick() + ( ( chrif->maintenance_endtime - chrif->maintenance_starttime )*1000 ), chrif->maintenance_duration, 0, 0 );
+ ShowStatus( CL_YELLOW "Maintenance has started." CL_RESET "\n" );
+ }
+ return false;
+}
+
+int chrif_maintenance_duration( int tid, int64 tick, int id, intptr data ) {
+ char aaa[255];
+ timer->delete( chrif->maintenance_timerid, chrif->maintenance_duration );
+ chrif->maintenance_timerid = 0;
+ safesnprintf( aaa, 255, "Maintenance mode has ended. Players are able to login now." );
+ intif->broadcast( aaa , strlen(aaa)+1, 0xFFFF00 );
+ chrif->maintenance_group = 0;
+ chrif->maintenance_starttime = (int)time(NULL);
+ chrif->maintenance_endtime = (int)time(NULL);
+ ShowStatus( CL_YELLOW "Maintenance has ended." CL_RESET "\n" );
+ return false;
+}
+
/*==========================================
*
*------------------------------------------*/
@@ -439,6 +496,57 @@ void chrif_connectack(int fd) {
sockt->datasync(fd, true);
chrif->skillid2idx(fd);
+ if ( SQL->Query( map->mysql_handle, "select minlv2connect, unix_timestamp( start_time ), unix_timestamp( end_time ), weekday( end_time ), hour( end_time ), minute( end_time ) from maintenance where id = ( select max(id) from maintenance )" ) == SQL_ERROR )
+ Sql_ShowDebug( map->mysql_handle );
+ else if ( SQL->NextRow( map->mysql_handle ) == SQL_SUCCESS ) {
+ char *data;
+ short weekday, hour, minute;
+ char* weekdayname[7] = { "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday" };
+ char am_pm[3], min_display[3];
+ size_t len;
+ if ( SQL->GetData( map->mysql_handle, 0, &data, NULL ) == SQL_SUCCESS )
+ chrif->maintenance_group = atoi(data);
+ if ( SQL->GetData( map->mysql_handle, 1, &data, &len ) == SQL_SUCCESS )
+ chrif->maintenance_starttime = atoi(data);
+ else
+ chrif->maintenance_starttime = 0;
+ if ( SQL->GetData( map->mysql_handle, 2, &data, NULL ) == SQL_SUCCESS )
+ chrif->maintenance_endtime = atoi(data);
+ if ( SQL->GetData( map->mysql_handle, 3, &data, NULL ) == SQL_SUCCESS )
+ weekday = atoi(data);
+ if ( SQL->GetData( map->mysql_handle, 4, &data, NULL ) == SQL_SUCCESS )
+ hour = atoi(data);
+ if ( SQL->GetData( map->mysql_handle, 5, &data, NULL ) == SQL_SUCCESS )
+ minute = atoi(data);
+ if ( hour == 0 ) {
+ hour = 12;
+ safesnprintf( am_pm, 3, "AM" );
+ }
+ else if ( hour < 12 )
+ safesnprintf( am_pm, 3, "AM" );
+ else {
+ hour = hour - 12;
+ safesnprintf( am_pm, 3, "PM" );
+ }
+ if ( minute < 10 )
+ safesnprintf( min_display, 3, "0%d", minute );
+ else
+ safesnprintf( min_display, 3, "%d", minute );
+ safesnprintf( chrif->maintenance_timeformat, 24, "%s, %d:%s %s", weekdayname[ weekday ], hour, min_display, am_pm );
+ }
+ if ( chrif->maintenance_starttime > time(NULL) ) {
+ int countdown = chrif->maintenance_starttime - (int)time(NULL);
+ if ( countdown > 60 )
+ chrif->maintenance_countid = timer->add( timer->gettick() + ( ( countdown % 60 )*1000 ), chrif->maintenance_countdown, 0, 0 );
+ else
+ chrif->maintenance_countid = timer->add( timer->gettick() + 1000, chrif->maintenance_countdown, 0, 0 );
+ ShowStatus( CL_YELLOW "Maintenance will start in %d min %d sec." CL_RESET "\n", countdown /60, countdown %60 );
+ }
+ else if ( chrif->maintenance_endtime > time(NULL) ) {
+ int countdown = chrif->maintenance_endtime - (int)time(NULL);
+ chrif->maintenance_timerid = timer->add( timer->gettick() + ( countdown *1000 ), chrif->maintenance_duration, 0, 0 );
+ ShowStatus( CL_YELLOW "Maintenance will end in %d min %d sec." CL_RESET "\n", countdown/60, countdown %60 );
+ }
}
/**
@@ -1753,4 +1861,7 @@ void chrif_defaults(void) {
chrif->parse = chrif_parse;
chrif->save_scdata_single = chrif_save_scdata_single;
chrif->del_scdata_single = chrif_del_scdata_single;
+
+ chrif->maintenance_countdown = chrif_maintenance_countdown;
+ chrif->maintenance_duration = chrif_maintenance_duration;
}
diff --git a/src/map/chrif.h b/src/map/chrif.h
index 11baaf5..aa66fc8 100644
--- a/src/map/chrif.h
+++ b/src/map/chrif.h
@@ -146,6 +146,15 @@ struct chrif_interface {
int (*parse) (int fd);
void (*save_scdata_single) (int account_id, int char_id, short type, struct status_change_entry *sce);
void (*del_scdata_single) (int account_id, int char_id, short type);
+ int (*maintenance_countdown) ( int tid, int64 tick, int id, intptr data );
+ int (*maintenance_duration) ( int tid, int64 tick, int id, intptr data );
+
+ int maintenance_group;
+ int maintenance_starttime;
+ int maintenance_endtime;
+ int maintenance_countid;
+ int maintenance_timerid;
+ char maintenance_timeformat[24];
};
struct chrif_interface *chrif;
diff --git a/src/map/clif.c b/src/map/clif.c
index d9acf07..1c2975b 100644
--- a/src/map/clif.c
+++ b/src/map/clif.c
@@ -9276,6 +9276,19 @@ void clif_parse_LoadEndAck(int fd,struct map_session_data *sd) {
#endif
bool first_time = false;
+ if ( sd->state.connect_new ) {
+ if ( chrif->maintenance_starttime > time(NULL) ) {
+ char aaa[255];
+ safesnprintf( aaa, 255, "Maintenance starts in %d min %d sec, last %d minutes. Server up by %s", ( chrif->maintenance_starttime - (int)time(NULL) ) /60, ( chrif->maintenance_starttime - (int)time(NULL) ) %60, ( chrif->maintenance_endtime - chrif->maintenance_starttime ) /60, chrif->maintenance_timeformat );
+ clif->message( sd->fd, aaa );
+ }
+ else if ( chrif->maintenance_endtime > time(NULL) ) {
+ char aaa[255];
+ safesnprintf( aaa, 255, "Server is currently in maintenance mode, will end in %d min %d sec on %s", ( chrif->maintenance_endtime - (int)time(NULL) ) /60, ( chrif->maintenance_endtime - (int)time(NULL) ) %60, chrif->maintenance_timeformat );
+ clif->message( sd->fd, aaa );
+ }
+ }
+
if(sd->bl.prev != NULL)
return;
diff --git a/src/map/pc.c b/src/map/pc.c
index 2372d31..122bae6 100644
--- a/src/map/pc.c
+++ b/src/map/pc.c
@@ -973,6 +973,11 @@ bool pc_authok(struct map_session_data *sd, int login_id2, time_t expiration_tim
int64 tick = timer->gettick();
uint32 ip = session[sd->fd]->client_addr;
+ if ( time(NULL) > chrif->maintenance_starttime && chrif->maintenance_endtime > time(NULL) && group_id < chrif->maintenance_group ) {
+ clif->authfail_fd( sd->fd, 1 );
+ return false;
+ }
+
sd->login_id2 = login_id2;
if (pc->set_group(sd, group_id) != 0) {