-
Content Count
1677 -
Joined
-
Last visited
-
Days Won
245
Reputation Activity
-
AnnieRuru got a reaction from hurtsky in Advance SQL commands
3. Choose a table type, MyISAM or InnoDB ?
https://stackoverflow.com/questions/20148/myisam-versus-innodb
Before MySQL 5.5,
MyISAM is mostly use for read-heavy + table locking storage engine = such as pvp ladder ( always select ... order by kill desc )
InnoDB is mostly use for write-heavy + row locking storage engine = such as quest script ( select ... from char_id ... only 1 row is retrieve )
After MySQL 5.6, (currently is 8.0)
just stick to InnoDB
there is only 1 reason MyISAM is better than InnoDB
- MyISAM use smaller disk usage than InnoDB
let's take a look at our MyISAM to InnoDB converter
https://github.com/HerculesWS/Hercules/blob/stable/sql-files/tools/convert_engine_innodb.sql
This converter is useful if you are using MySQL 5.6 or above
There are 4 tables that are commented out
the reason is simple, these 4 tables only read once and forgotten when server is live
since MyISAM is good at reading (SELECT) + smaller disk usage, its no use to convert these 4 tables into InnoDB
3a How to index a table properly
http://mysql.rjweb.org/doc.php/index_cookbook_mysql
http://www.dbta.com/Columns/DBA-Corner/Top-10-Steps-to-Building-Useful-Database-Indexes-100498.aspx
a simple thumb of rule, anything that is SELECT .... WHERE `field` = .....
that `field` has to be index
let's take a look at this PVP Ladder script that use Kill/Death ratio
CREATE TABLE `pvpladder` ( `char_id` INT(11), `name` VARCHAR(23), `kills` INT(11), `death` INT(11), PRIMARY KEY (`char_id`), KEY (`kills`, `death`) ) ENGINE = InnoDB; prontera,155,186,6 script PVP Ladder 1_F_MARIA,{ .@nb = query_sql( "SELECT `name`, `kills`/(`death`+1) FROM `pvpladder` WHERE `kills` > 0 ORDER BY `kills`/(`death`+1) DESC LIMIT 10", .@name$, .@ratio$ ); if ( !.@nb ) { mes "no entry"; close; } mes "Current Ranking :"; for ( .@i = 0; .@i < .@nb; ++.@i ) mes "No."+(.@i +1)+" ["+ .@name$[.@i] +"] "+ .@ratio$[.@i] +" kill"; close; OnPCKillEvent: if ( killedrid == getcharid(3) ) { // killing self should only increase death count. EG: Grand-cross query_sql "INSERT INTO `pvpladder` VALUES ( "+ getcharid(0) +", '"+ escape_sql( strcharinfo(0) )+"', 0,1 ) ON DUPLICATE KEY UPDATE `death` = `death` +1"; end; } query_sql "INSERT INTO `pvpladder` VALUES ( "+ getcharid(0) +", '"+ escape_sql( strcharinfo(0) )+"', 1,0 ) ON DUPLICATE KEY UPDATE `kills` = `kills` +1"; attachrid killedrid; query_sql "INSERT INTO `pvpladder` VALUES ( "+ getcharid(0) +", '"+ escape_sql( strcharinfo(0) )+"', 0,1 ) ON DUPLICATE KEY UPDATE `death` = `death` +1"; end; } This kind of query -> ORDER BY kills/death, needs to index them together like this
KEY (`kills`, `death`) 3b. Why you shouldn't use `char_reg_num_db` table
blame Euphy for spreading this technique
There are 2 reasons why you shouldn't even touch all these variable tables
Reason no.1 This table is sorely meant for server usage
Once these data is loaded, it is process internally, and only save character data according to this configuration
Reason no.2 The `value` field is not index !
This line has ORDER BY `value`, try recheck our main.sql file
CREATE TABLE IF NOT EXISTS `acc_reg_num_db` ( `account_id` INT(11) UNSIGNED NOT NULL DEFAULT '0', `key` VARCHAR(32) BINARY NOT NULL DEFAULT '', `index` INT(11) UNSIGNED NOT NULL DEFAULT '0', `value` INT(11) NOT NULL DEFAULT '0', PRIMARY KEY (`account_id`,`key`,`index`), KEY `account_id` (`account_id`) ) ENGINE=MyISAM; SQL will search through every single line in the `value` field if that column isn't index
Of course you can ... do ALTER table to add KEY to the `value` field
but this table has already optimized in that way for server usage
the more field you index into the table, the more disk usage space it use
Conclusion : If you want to make a custom script, then make a custom table. Leave these table alone !
-
AnnieRuru got a reaction from hurtsky in Advance SQL commands
2. How to build a case-sensitive table
this is the answer I found
http://dba.stackexchange.com/questions/15250/how-to-do-a-case-sensitive-search-in-where-clause
by default, the table creation use charset = latin1;
means it couldn't do a case-sensitive search
if you want to do a case-sensitive in a query, use BINARY
SELECT * FROM `char` WHERE `name` = BINARY('AnnieRuru'); however using BINARY might have performance hit if it is a big table
so its more recommend to convert your SQL table to collate with latin1_general_cs
let's say this is a sample table
CREATE TABLE `test` ( `id` INT(11) PRIMARY KEY AUTO_INCREMENT, `name` VARCHAR(23) )ENGINE = InnoDB; do an ALTER table syntax
ALTER TABLE `test` MODIFY COLUMN `name` VARCHAR(23) COLLATE latin1_general_cs; or just put it into the table creation
CREATE TABLE `test` ( `id` INT(11) PRIMARY KEY AUTO_INCREMENT, `name` VARCHAR(23) )ENGINE = InnoDB DEFAULT CHARSET = latin1 COLLATE latin1_general_cs;
-
AnnieRuru got a reaction from Cabrera in Advance SQL commands
1. When to use escape_sql script command
.
input .@haha$; dispbottom .@haha$; dispbottom escape_sql(.@haha$); it doesn't has much differences, because it only affect 3 special characters
' <- single quotation mark
" <- double quotation mark
\ <- left slash
if I input -> haha"lala'hehe <-
it will return -> haha\"lala\'hehe <-
this is what we call, Escape a character
in hercules script, we also know we can use " symbol in any string input
mes "Susan says :\" Today I ate 3 eggs \"."; where in the game client, you can see the " symbol in the npc msg box
let's say I have a sql script like this
prontera,153,171,5 script Show Characters 1_F_MARIA,{ mes "input name, I'll show you all characters name it has on that player's account"; input .@name$; .@nb = query_sql("SELECT `char_id`, `name` FROM `char` WHERE `name` LIKE '"+ .@name$ +"'", .@cid, .@name$); if ( !.@nb ) { mes "no result"; close; } for ( .@i = 0; .@i < .@nb; ++.@i ) mes .@cid[.@i] +" "+ .@name$[.@i]; close; } this script has a possibility to be hacked
because to perform sql injection, I can enclose the string with quotation mark, then use another sql command to hack
BUT with an escape_sql command, if the user want to enclose the string with quotation mark to hack the script
the escape_sql command escaped the string, the quotation mark the user input will be escaped
thus the script will become impossible to hack
just now that script was for string input
prontera,153,171,5 script Show Characters 1_F_MARIA,{ mes "input account ID, I'll show you all characters name it has on that player's account"; input .@aid$; .@nb = query_sql("SELECT `char_id`, `name` FROM `char` WHERE `account_id` = "+ escape_sql(.@aid$), .@cid, .@name$); if ( !.@nb ) { mes "no result"; close; } for ( .@i = 0; .@i < .@nb; ++.@i ) mes .@cid[.@i] +" "+ .@name$[.@i]; close; } this is another stupid case.
1. the scripter use string input while the script just needed a number
2. even with escape_sql command over there, there is no quotation mark at all
yes this script also has a risk to be hack
because escape_sql only escape quotation mark.
that hacker don't even have to input quotation mark because it is a number
and an injection query can be sent without any quotation mark input
there are 2 ways to solve this
either use numeric variable for the input command
or enclose that ....
..... WHERE `account_id` = '"+ escape_sql(.@aid$) +"'", .... with single quotation mark, when the hacker input a quotation mark will be escaped by escape_sql command
Reference : https://www.w3schools.com/sql/sql_injection.asp
escape_sql command for another thing is
if the player register their names containing ' or ", these characters are escaped
only happens when the server have no restriction on the creation of players name
hercules\conf\char\char-server.conf
// Manage possible letters/symbol in the name of charater. Control character (0x00-0x1f) are never accepted. Possible values are: // NOTE: Applies to character, party and guild names. // 0: no restriction (default) // 1: only letters/symbols in 'name_letters' option. // 2: Letters/symbols in 'name_letters' option are forbidden. All others are possibles. name_option: 1
and this was what happened to my SQL dota pvpladder script
Silo's Babies <-- this is a guild name
you can see the 5th string has a single quotation mark
with escape_sql command, that string will turn into
Silo\'s Babies <-- the quotation mark is escaped when send to sql query
-
AnnieRuru got a reaction from wOni in Advance SQL commands
As usual, I only write advance guides
This guide is a compilation of SQL commands that I have used, or Questions answered on the forum
every single subject here are related to Hercules/Ragnarok Online in some ways, so you won't feel bored reading them XD
Table of Content
1. When to use *escape_sql script command
2. How to build a case-sensitive table
3. Choose a table type, MyISAM or InnoDB ?
3a. How to index a table properly
3b. Why you shouldn't use `char_reg_num_db` table
4. AUTO_INCREMENT
5. How to do IF-ELSE in SQL query ?
5a. How to update multiple rows on different conditions in a single query
6. How to show the current rank of the player
7. INSERT INTO ... SELECT ...
8. Table JOIN vs AS
9. What is the maximum string limit for *query_sql
9a. UNION
This topic is now open to Suggestions, Ideas, Improvements, and Questions ~
I'm sure many of you have some questions since the creation of this topic
You may also post up your tricks if you want to share with us
-
AnnieRuru got a reaction from xVec in King of Emperium Hill
got a PM from rAthena member ask me to fix this
yeah both rathena patch and hercules plugin ... all broken
so ....
update to 1.2
Script
Plugin for Hercules
Patch for rAthena
-
AnnieRuru got a reaction from Begin in King of Emperium Hill
got a PM from rAthena member ask me to fix this
yeah both rathena patch and hercules plugin ... all broken
so ....
update to 1.2
Script
Plugin for Hercules
Patch for rAthena
-
-
-
AnnieRuru got a reaction from Alrighty in Adding a Custom Map Cache File
1st of all, sorry I only know windows environment -- windows sux !!
2nd, yeah I agree too, this took me 2 days to figure out how to do this
reference topic
Prelude
make sure you already know how to install a plugin
http://herc.ws/wiki/Building_HPM_Plugin_for_MSVC
yup ~ use the new method ~ ( maybe I should've remove the old method already ... )
and add "mapcache" to your "hercules\conf\plugins.conf"
Run command prompt
1. [Windows Key] + [R] -> type cmd
https://drive.google.com/file/d/19Ni-NUAZusaCgEX6xnXxasZDLHtkW-N-/view?usp=sharing
2. point to your Hercules emulator folder, and type mapserver.exe --help
https://drive.google.com/file/d/1EpB4jxaB3VAO0XzB9gJq7t6fmtBb4RZ5/view?usp=sharing
3. type mapserver.exe --map <YourMap>
https://drive.google.com/file/d/1Q68HSNaxvGEwsm6UeHEcgL2BY-JpKNgV/view?usp=sharing
now that you know the commands ... lets do it easier way
Windows Execution File -- Create Shortcut
1. point to your map-server.exe, and create shortcut
https://drive.google.com/file/d/15szzAa8Fuef9UQUjB3rsygNafoLtr6Tm/view?usp=sharing
2. right-click, Properties, and edit the Target Location/Target (this example is my hercules directory)
D:\Ragnarok\Hercules\map-server.exe --map <YourMap> https://drive.google.com/file/d/1hwqPrJE4M53QkoAeiuA4pFCF1A8ZHPpz/view?usp=sharing
whenever I want to add new maps, I just need to edit the Target field, and double click the program ~ fast and easy ~
Fun Facts !!
do you know you can use GM command in map-server.bat ?
https://drive.google.com/file/d/15gOf4vgl9HWc58Q8Jdn9Vbbza5lY5ek6/view?usp=sharing
-
AnnieRuru reacted to meko in Array manipulation functions
released version 10, which adds array_sort() and array_rsort()
uses the Lomuto implementation of the Quicksort algorithm
works with both string arrays (arr$) and integer arrays (arr)
-
AnnieRuru reacted to meko in Array manipulation functions
View File Array manipulation functions
This script provides various array manipulation functions, and more might be added in the future.
All of those functions (except the arithmetic ones) work with both integer and string arrays.
The start of the array is always implicitly index 0, unless an index is specified, ie @array[index]
array_pad(<array>, <size>, <value>)
pads the array left or right with <value> until it reaches <size> size. If <size> is negative it will pad left.
> returns the number of added entries
setarray(.@foo, 1, 2, 3, 4, 5); // initialize the array array_pad(.@foo, 8, 69); // => 3 // array is now: 1, 2, 3, 4, 5, 69, 69, 69 setarray(.@foo, 1, 2, 3, 4, 5); // initialize the array array_pad(.@foo, -8, 69); // => 3 // array is now: 69, 69, 69, 1, 2, 3, 4, 5
array_replace(<array>, <needle>, <replacement>{, <neq>})
finds every occurrence of <needle> within the array and replaces it with <replacement>. if <neq> is true, finds entries that do not match instead
> returns the number of changed entries setarray(.@foo, 1, 1, 3, 1, 5); // initialize the array array_replace(.@foo, 1, 69); // => 3 // array is now: 69, 69, 3, 69, 5
array_find(<array>, <needle>{, <neq>})
finds the first occurrence of <needle> within the array. if <neq> is true, finds entries that do not match instead
> returns the index, or if none is found returns -1 setarray(.@foo, 1, 2, 3, 4, 5); // initialize the array array_find(.@foo, 3); // => 2 array_find(.@foo, 1); // => 0 array_find(.@foo, 6); // => -1
array_rfind(<array>, <needle>{, <neq>})
like array_find, but finds the last occurrence. if <neq> is true, finds entries that do not match instead
> returns the index, or if none is found returns -1 setarray(.@foo, 1, 2, 3, 4, 3); // initialize the array array_rfind(.@foo, 3); // => 4 array_rfind(.@foo, 4); // => 3 array_rfind(.@foo, 6); // => -1
array_exists(<array>, <needle>{, <neq>})
very similar to array_find() but it instead just checks if it exists or not. if <neq> is true, finds entries that do not match instead > returns true or false setarray(.@foo, 1, 2, 3, 4, 5); // initialize the array array_exists(.@foo, 3); // => true array_exists(.@foo, 6); // => false
array_count(<array>, <needle>{, <neq>})
similar to array_find() but iterates through the whole array. if <neq> is true, finds entries that do not match instead
> returns the total number of occurrences of <needle> setarray(.@foo, 1, 69, 3, 69, 5); // initialize the array array_count(.@foo, 69); // => 2
array_entries(<array>)
a wrapper around array_count(). behaves similarly to getaraysize() but does not count holes
> returns the number of non-empty entries setarray(.@foo, 1, 2, 0, 0, 5); // initialize the array getarraysize(.@foo); // => 5 array_entries(.@foo); // => 3
array_remove(<array>, <needle>{, <neq>})
finds and removes every occurrence of <needle> from the array, while shifting left. if <neq> is true, finds entries that do not match instead
> returns the number of removed entries setarray(.@foo, 1, 69, 3, 69, 5); // initialize the array array_remove(.@foo, 69); // => 2 // array is now: 1, 3, 5
array_reverse(<array>)
reverses the array
> returns true setarray(.@foo, 1, 2, 3, 4, 5); // initialize the array array_reverse(.@foo); // => true // array is now: 5, 4, 3, 2, 1
array_sum(<array>)
iterates through the whole array to perform an arithmetic addition
> returns the sum of every entries of the array setarray(.@foo, 1, 2, 3, 4, 5); // initialize the array array_sum(.@foo); // ((((1 + 2) + 3) + 4) + 5) => 15
array_difference(<array>)
iterates through the whole array to perform an arithmetic subtraction
> returns the difference of every entries of the array setarray(.@foo, 1, 2, 3, 4, 5); // initialize the array array_difference(.@foo); // ((((1 - 2) - 3) - 4) - 5) => -13
array_product(<array>)
iterates through the whole array to perform an arithmetic multiplication
> returns the product of every entries of the array setarray(.@foo, 1, 2, 3, 4, 5); // initialize the array array_product(.@foo); // ((((1 * 2) * 3) * 4) * 5) => 120
array_quotient(<array>)
iterates through the whole array to perform an arithmetic division
> returns the quotient of every entries of the array setarray(.@foo, 1, 2, 3, 4, 5); // initialize the array array_quotient(.@foo); // ((((1 / 2) / 3) / 4) / 5) => 0
array_shift(<array>)
removes the first entry of the array, while shifting left
> returns the value of the removed entry setarray(.@foo, 1, 2, 3, 4, 5); // initialize the array array_shift(.@foo); // => 1 // array is now: 2, 3, 4, 5
array_unshift(<array>, <value>)
adds <value> to the start of the array, while shifting right
> returns the new size of the array setarray(.@foo, 1, 2, 3, 4, 5); // initialize the array array_unshift(.@foo, 69); // => 6 // array is now: 69, 1, 2, 3, 4, 5
array_pop(<array>)
removes the last entry of the array
> returns the value of the removed entry setarray(.@foo, 1, 2, 3, 4, 5); // initialize the array array_pop(.@foo); // => 5 // array is now: 1, 2, 3, 4
array_push(<array>, <value>)
adds <value> to the end of the array
> returns the new size of the array setarray(.@foo, 1, 2, 3, 4, 5); // initialize the array array_push(.@foo, 69); // => 6 // array is now: 1, 2, 3, 4, 5, 69
array_shuffle(<array>)
shuffles the array
> returns true setarray(.@foo, 1, 2, 3, 4, 5); // initialize the array array_shuffle(.@foo); // => true // array is now: 1, 4, 2, 3, 5 (example, unpredictable)
array_unique(<array>{, <threshold>})
allows array entries to appear up to <threshold> times (1 by default) and removes the extraneous ones. useful to remove duplicate entries
> returns the number of removed entries
setarray(.@foo, 1, 3, 3, 4, 5); // initialize the array array_unique(.@foo); // => 1 // array is now: 1, 3, 4, 5
array_diff(<base array>, <array>{, <array>...}, <result array>)
compares the base array against one or more other arrays and fills the result array with the entries in base array that are not present in any of the other arrays
> returns the number of entries not found in other arrays
setarray(.@base, 1, 2, 3, 4, 5, 6, 7, 8); // initialize the base array // fill the arrays to compare with the base array: setarray(.@foo, 2, 3, 4, 5, 6, 7, 8); // missing "1" setarray(.@bar, 1, 2, 3, 4, 6, 7, 8); // missing "5" setarray(.@baz, 1, 2, 3, 4, 5, 6, 7); // missing "8" // compare foo, bar and baz against base, and fill result: array_diff(.@base, .@foo, .@bar, .@baz, .@result); // => 3 // .@result is now: 1, 5, 8
array_filter(<array>, "<function>")
filters the array using a function that is tested against every entries. if the function returns false, the relevant entry is removed and the array is shifted left
> returns the number of removed entries
function script is_prime { if (getarg(0) <= 1) return false; for (.@i = 2; .@i <= getarg(0) / 2; ++.@i) if ((getarg(0) % .@i) == 0) return false; return true; } setarray(.@foo, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); array_filter(.@foo, "is_prime"); // => 9 // array is now: 2, 3, 5, 7, 11, 13
array_sort(<array>)
sorts the array in ascending order
> returns true
setarray(.@foo, 2, 1, 8, 4, 5, 7, 6, 3); // initialize the array array_sort(.@foo); // => true // array is now: 1, 2, 3, 4, 5, 6, 7, 8
array_rsort(<array>)
sorts the array in descending order
> returns true
setarray(.@foo, 2, 1, 8, 4, 5, 7, 6, 3); // initialize the array array_rsort(.@foo); // => true // array is now: 8, 7, 6, 5, 4, 3, 2, 1
Requires Hercules of June 24 2017 or newer version
--------------------------------------------------------------------------------------
This script was made by me, for The Mana World + Evol.
License: public domain (CC0)
Submitter meko Submitted 05/29/17 Category Quest, Shops, Functions & Algorithms
-
AnnieRuru reacted to meko in Array manipulation functions
@AnnieRuru I just released version 9, which adds array_filter() and makes array_shuffle() use the Durstenfeld implementation of the Fisher-Yates algorithm
-
AnnieRuru reacted to Easycore in requesting hexed client compatible with 20170705
RagExes until 2018-03-28:
Updated NEMO (support 2017-2018 clients):
Translated files from data and system folders:
https://github.com/Asheraf/Translation
https://github.com/zackdreaver/ROenglishRE
Note: Change langtype to 1 if you want huge fonts.
Note 2: If the selected ragexe use ExternalSettings.lua check this topic:
-
-
-
-
-
-
-
-
AnnieRuru got a reaction from caspe in Suggestion for restricted equipment (making a new conf for it)
http://upaste.me/f94d11052d9751e97
this one should go inside SVN
EDIT: suddenly I feel this one can be improve ....
ok this one better
http://upaste.me/d2ac11053eed06c03
-
AnnieRuru got a reaction from IndieRO in King of Emperium Hill
I think its better to have a release topic for this instead of me update the script across separate topics
Download: Hercules 1.3
Script
Plugin for Hercules
Download: rAthena 1.2
Script.
Patch for rAthena
what this event do ? ( huh ? so popular script and I still need to explain ? )
1. make a guild
2. join this event
3. whack the emperium
4. defends it until times up
hahaha ....
How to configure the time:
L_start: <-- the label to start the event
change OnClock2000: into OnSat2000: to start this event on Saturday 8pm
L_end: <-- the label to end the event
change OnClock2030: into OnSat2030: to end this event on Saturday 8:30pm,
effectively makes this event runs 30 minutes
Frequently Asked Questions:
Question : why the Guild member can hit their own Emperium ?
Answer : because you didn't patch and recompile
Question: there is an exploit in this event, guild master can use Emergency Recall to abuse the prize
Answer : I already fixed it in this topic, now the prize reward will be given after the winner warp outside the map
original topic from eathena forum
http://www.eathena.ws/board/index.php?showtopic=174222
yeah ... I have been fixing this script since 7 years ago
-
AnnieRuru got a reaction from Psy Ops in who has AnnieRuru's PVP Ladder with announcement files and SQL queries?
just mirror ... in-case
dota_pvpladder.2.9.txt
dotasoundeffect_2.rar
actually I want to drop this script
just ... I have no idea it can become so popular ...
that "replace into" was slower than "update" statement, I learned that only after 3 years completed this script
I was using 'replace into' just because I wanted to squeeze that accessing 12 times query_sql into just 4 times
and ultramage also proposed to make the table make a huge 'update' every 1 minute to safe further memory
however if changing 'replace into' into 'update' might need to update the whole script
and I have no motivation to improve this script, I rather focus on battleground scripts
-
AnnieRuru got a reaction from caspe in map_zone_db.conf allows to restrict an ITEM TYPE
ok ... its my turn to give suggestion time ..
http://rathena.org/board/topic/77088-certain-map-weapon-restriction/?p=239342
noitem mapflag meant for rathena
when compare my code and hercules map_zone_db.conf
hercules can already restrict items by ID
but my modifications can allow to restrict an item type
example
pvp_y_1-1 mapflag noitem 0this pvp map cannot use healing itemsevent_gm mapflag noitem 4,5this gm hosting event will disallow players to equip any kind of equipments
so how about hercules have the same thing
{ name: "PvP no Pot" inherit: ( "PvP" ) disabled_items: { IT_HEALING: true }}, { name: "GM event" disabled_items: { IT_WEAPON: true IT_ARMOR: true }}, -
AnnieRuru got a reaction from Kairedia in Maintenance mode
Download: 1.5
plugin
create table maintenance ( id int primary key auto_increment, account_id int, name varchar(23), reason varchar(99), minlv2connect tinyint, order_time datetime, start_time datetime, end_time datetime ) engine = innodb; .
remember to enable HPMHooking to enable this modification
plugins_list: [ /* Enable HPMHooking when plugins in use rely on Hooking */ "HPMHooking", .
.
Note:
sometimes the server countdown jumps 1 second ahead
this is normal because the timetick from time->add is unstable
so I use unix_time to synchronize the countdown to server time
.
.
so, if you found some script/source code having bugs and you need to shut down your server for a short while
then you come to the right place
.
@maintenance <Group ID can stay 1~99> <duration to kick in minute> <maintenance duration in minute> <reason> then a GM99 can commence the maintenance
Example : '@maintenance 40 5 10 need to fix announcer script'
every player with group ID 40 and below will be kick after 5 minutes
and the server will start counting down by an announcement,
during the maintenance of 10 minutes, group ID 40 and below will deny from login into the server
`maintenance` table will also generate a new line, with the `reason` field as 'need to fix announcer script'
which is useful to know when and how many times you did emergency server shutdown
though, the actual reason for using SQL is to persist the data after server shutdown
so the server will continue being in maintenance mode despite how many times you have shut down the server
until it times up ( `end_time` field ), or manually do `@maintenanceoff`
Note:
you can't generate a new line using 'INSERT INTO' Sql syntax when server is online
because I declare a bunch of variables to for them, for the purpose of saving memory consumption
you have to login the game and type `@maintenance` to initiate the maintenance mode, otherwise it wont work.
.
.
.
@maintenanceoff if you have already finished fixing the script/source code, and there's still a lot of time left
you can type '@maintenanceoff' to immediately turn off the maintenance mode so players can login before the schedule.
.
.
.
.
-- Script commands --
.
*maintenance <Group ID can stay 1~99>, <duration to kick in minute>, <maintenance duration in minute> { , <reason> }; .
.
actually I have no idea why I wanna make a script command ... maybe just for fun ?
.
- script jsdfksdj FAKE_NPC,{ OnMon0255: maintenance 40, 5, 60; end; } .
this will make an announcement on Monday, 2:55AM that the server will have a regular server maintenance starts from 3AM to 4AM
during that time, player with group ID 40 will be kicked and blocked from entering the server
the `reason` field in `maintenance` table will be defaulted to '*Regular server maintenance*'
.
maintenance 40, 5, 60, "系统保养";
this will overwrite the `reason` field in `maintenance` table to '系统保养' instead of regular maintenance
.
.
*maintenanceoff { <reason> }; uhh ... useless I think ...
.
.
*maintenancecheck( <type> ); use 'maintenance()' to check the server is currently in maintenance mode or not
return 0 if server is normal
return 1 if server is going to have maintenance
return 2 if server is having maintenance
all other types are meant to myself to debug this junk